您的位置:首页 > 理论基础 > 计算机网络

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

2018-06-26 09:04 429 查看

题目链接

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]
 - 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\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: