• BZOJ 1495 [NOI2006]网络收费(暴力DP)


    题意

    给定一棵满二叉树,每个叶节点有一个状态0/10/1,对于每两个叶节点i,ji,j,如果这两个叶节点状态相同但他们的LCALCA所管辖的子树中的与他们状态相同的叶节点个数较少(少于1/21/2),则会产生2fij2f_{ij}的代价,如果状态不同,则产生fijf_{ij}的代价,如果状态相同且LCALCA管辖子树中与他们状态相同叶节点个数较多,则不产生代价,现在每个节点可以变更状态,但变更状态也有自己的代价,求最小总代价 。

    题解

    在满二叉树上暴力枚举这个点子树中是00多还是11多,然后递归下去DPDP合并。时间复杂度是O(2n2nn)O(2^ncdot 2^ncdot n)的。对于每一个叶子结点,到根的路径最长只有nn,所有情况就是2n2^n,所以所有叶子节点加起来的时间复杂度是2n2n2^ncdot 2^n,由于还要枚举这条路径上的点算代价,所以就再乘个nn

    费用的计算方法就是:
    对于点对(i,j)(i,j)的贡献,如果LCALCAii异色,费用就加上一个fijf_{ij},如果LCALCAjj异色,就再加上一个fijf_{ij}。可以发现这样算出来的答案恰好符合题意。LCALCA的颜色就表示子树下面11多还是00多,这个是暴力枚举的。

    具体实现看代码。

    CODE

    dp[i][j]dp[i][j]表示在ii的子树里选了jj11的最小费用。

    #pragma GCC optimize (3)
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int MAXN = 2060;
    const LL INF = 1ll<<40;
    int f[MAXN][2], n, all, a[MAXN];
    LL dp[MAXN][MAXN], cst[MAXN][12];
    bool clr[12];
    void dfs(int x, int dep) {
    	for(int i = 0; i <= all; ++i) dp[x][i] = INF;
    	if(dep == n) {
    		dp[x][0] = f[x-all][0];
    		dp[x][1] = f[x-all][1];
    		for(int i = 0; i < n; ++i) dp[x][clr[i]^1] += cst[x-all][i];
    		return;
    	}
    	int half = 1<<(n-dep-1);
    	clr[dep] = 0; dfs(x<<1, dep+1), dfs(x<<1|1, dep+1);
    	for(int i = 0; i <= half; ++i)
    		for(int j = 0; i+j <= half; ++j)
    			dp[x][i+j] = min(dp[x][i+j], dp[x<<1][i] + dp[x<<1|1][j]);
    	
    	clr[dep] = 1; dfs(x<<1, dep+1), dfs(x<<1|1, dep+1);
    	for(int i = 0; i <= half; ++i)
    		for(int j = half+1-i; j <= half; ++j)
    			dp[x][i+j] = min(dp[x][i+j], dp[x<<1][i] + dp[x<<1|1][j]);
    }
    int lca_dep(int u, int v) {
    	for(int i = n-1; i >= 0; --i) if((u>>i) != (v>>i)) return n-i-1;
    }
    int main () {
    	scanf("%d", &n); all = 1<<n;
    	for(int i = 0; i < all; ++i) scanf("%d", &a[i]);
    	for(int i = 0; i < all; ++i) f[i][a[i]] = 0, scanf("%d", &f[i][a[i]^1]);
    	for(int i = 0; i < all; ++i)
    		for(int j = i+1; j < all; ++j) {
    			int k = lca_dep(i, j), v; scanf("%d", &v);
    			cst[i][k] += v, cst[j][k] += v;
    		}
    	dfs(1, 0);
    	printf("%lld
    ", *min_element(dp[1], dp[1] + all + 1));
    }
    
  • 相关阅读:
    数学角度看设计模式之观察者模式
    XML、JSON数据结构解析
    [理解ASP.NET Core框架]一个五十行的控制台Web
    .Net Core 学习 (1)
    SqlServer windowss身份登陆和sa身份登陆
    学习51单片机——秒表分享
    C语言中函数声明实现的位置
    java DOM4J 读取XML
    服务器与Linux操作系统基础原理
    Go语言实现数据结构(一)单链表
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039207.html
Copyright © 2020-2023  润新知