鱼肉炸弹(树形dp)
发布日期:2021-05-08 21:51:14 浏览次数:41 分类:精选文章

本文共 1887 字,大约阅读时间需要 6 分钟。

为了解决这个问题,我们需要找到一种方法来使用K枚鱼肉炸弹,使得每个楼被看守的猫的数量Si中的最大值尽可能小。我们可以通过构建伪二叉树并使用动态规划来解决这个问题。

方法思路

  • 构建伪二叉树:首先,我们将建筑按照高度排序,构建一个伪二叉树。根节点是最高的建筑,左子树是比它矮的建筑,右子树同理。

  • 动态规划:使用动态规划来计算每个节点使用不同数量炸弹时的最大Si值。我们定义f[x][j]为在节点x使用j枚炸弹时的最大Si值。

  • 状态转移:在动态规划中,考虑左子树和右子树的炸弹分配情况,计算每个节点的最大Si值。

  • 解决代码

    #include 
    #include
    using namespace std;long long n, k, BOSS, h[1000005], c[1000005], b[1000005], f[1000005][6];struct node { long long l, r;} a[1000005];long long maketree(long long l, long long r) { if (l > r) return 0; if (l == r) return l; long long o = 0, mid = 0; for (long long i = l; i <= r; ++i) { if (h[i] > o) { o = h[i]; mid = i; } } a[mid].l = maketree(l, mid - 1); a[mid].r = maketree(mid + 1, r); return mid;}void dfs(long long x) { b[x] = 1; if (a[x].l != 0 && !b[a[x].l]) dfs(a[x].l); if (a[x].r != 0 && !b[a[x].r]) dfs(a[x].r); for (long long i = 0; i <= k; ++i) { for (long long j = 0; j <= k - i; ++j) { if (i + j < k) { f[x][i + j] = min(f[x][i + j], max(f[a[x].l][i], f[a[x].r][j]) + c[x]); if (f[x][i + j + 1] > max(f[x][i + j + 1], max(f[a[x].l][i], f[a[x].r][j]) + c[x])) { f[x][i + j + 1] = max(f[x][i + j + 1], max(f[a[x].l][i], f[a[x].r][j]) + c[x]); } } else { f[x][i + j] = max(f[x][i + j], max(f[a[x].l][i], f[a[x].r][j]) + c[x]); } } }}int main() { memset(f, 0x3f, sizeof(f)); f[0][0] = 0; scanf("%lld%lld", &n, &k); for (long long i = 1; i <= n; ++i) { scanf("%lld%lld", &h[i], &c[i]); } BOSS = maketree(1, n); dfs(BOSS); cout << f[BOSS][k] << endl;}

    代码解释

  • 构建伪二叉树:使用maketree函数构建树结构,找到每个节点的左和右子树。

  • 动态规划:定义f[x][j]表示在节点x使用j枚炸弹时的最大Si值。使用dfs函数进行深度优先搜索,计算每个节点的动态规划状态。

  • 状态转移:在每个节点上,枚举左子树和右子树的炸弹分配情况,计算最大Si值,并更新状态。

  • 通过这种方法,我们可以在给定的K枚炸弹中找到使Si的最大值最小的方案。

    上一篇:P1137 旅行计划(拓扑排序)
    下一篇:P2515 [HAOI2010]软件安装(树形dp)

    发表评论

    最新留言

    路过按个爪印,很不错,赞一个!
    [***.219.124.196]2025年04月12日 00时59分21秒