BZOJ1495 [NOI2006]网络收费 【树形dp + 状压dp】

题目链接

BZOJ1495

题解

观察表格,实际上就是分(A)多和(B)两种情况,分别对应每个点选(A)权值或者(B)权值,所以成对的权值可以分到每个点上
所以每个非叶节点实际对应一个状态,表示子树(AB)数量关系
(f[i][j][s])表示节点(i)子树中选了(j)(A),其祖先的状态为(s)的最小代价
空间可能开不下,但容易发现(j + s)(2^{N + 1})数量级,所以可以合并到一维
转移时枚举子树中的(A)即可

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 1050,maxm = 100005,INF = 1000000000;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
	return out * flag;
}
int f[maxn << 1][1 << 12],F[maxn][maxn],sta[maxn],C[maxn],L[maxn],R[maxn],M[maxn];
int n,N;
void dfs(int u,int l,int r,int d){
	if (l == r){
		int maxv = (1 << N) - 1,v;
		for (int s = 0; s <= maxv; s++){
			int e = s,sumA = 0,sumB = 0;
			for (int j = 1; j <= N; j++,e >>= 1){
				if (e & 1){
					v = (u >> j);
					if (l > M[v]) sumB += F[l][M[v]] - F[l][L[v] - 1];
					else sumB += F[l][R[v]] - F[l][M[v]];
				}
			}
			sumA = F[l][n] - sumB;
			f[u][s << (N + 1 - d) | 1] = sumA + sta[l] * C[l];
			f[u][s << (N + 1 - d)] = sumB + (!sta[l]) * C[l];
			//if (sumA < 0 || sumB < 0) puts("LXT");
		}
		return;
	}
	int mid = l + r >> 1;
	L[u] = l; R[u] = r; M[u] = mid;
	dfs(ls,l,mid,d + 1);
	dfs(rs,mid + 1,r,d + 1);
	int maxv = (1 << d) - 1,b = N + 1 - d;
	for (int s = 0; s <= maxv; s++){
		for (int Al = 0; Al <= (mid - l + 1); Al++)
			for (int Ar = 0; Ar <= (r - mid); Ar++){
				if (Al + Ar < (r - l + 1) - Al - Ar){
					int e = (s << b),t = (s << b) + Al + Ar;
					f[u][t] = min(f[u][t],f[ls][e + Al] + f[rs][e + Ar]);
				}
				else {
					int e = ((s << 1 | 1) << b - 1),t = (s << b) + Al + Ar;
					f[u][t] = min(f[u][t],f[ls][e + Al] + f[rs][e + Ar]);
				}
			}
	}
}
int main(){
	memset(f,0x3f3f3f3f,sizeof(f));
	N = read(); n = 1 << N;
	REP(i,n) sta[i] = read();
	REP(i,n) C[i] = read();
	REP(i,n) for (int j = i + 1; j <= n; j++) F[i][j] = F[j][i] = read();
	REP(i,n) for (int j = 1; j <= n; j++) F[i][j] += F[i][j - 1];
	dfs(1,1,n,0);
	int ans = 0x3f3f3f3f,maxv = (1 << N + 1) - 1;
	for (int i = 0; i <= maxv; i++) ans = min(ans,f[1][i]);
	printf("%d
",ans);
	return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/9227389.html