题解 P2465 【[SDOI2008]山贼集团】
xtx1092515503 · · 题解
这里介绍一种又快又短的可爱代码。
首先,我们预处理一个数组
然后,我们开始DP。设
然后开始树上背包。明显这里应该使用
最后统计额外消耗。枚举
总复杂度
代码(883B):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,q,lim;
ll f[110][1<<12],g[1<<12];
vector<int>v[110];
void dfs(int x,int fa){
for(int i=0;i<lim;i++)f[x][i]=f[x][i^(i&-i)]+f[x][i&-i];
for(auto y:v[x]){
if(y==fa)continue;
dfs(y,x);
for(int i=lim-1;i;i--)for(int j=i;j;j=(j-1)&i)f[x][i]=max(f[x][i],f[x][i^j]+f[y][j]);
}
for(int i=0;i<lim;i++)f[x][i]+=g[i];
}
int main(){
scanf("%d%d",&n,&m),lim=1<<m;
for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
for(int i=1;i<=n;i++)for(int j=0,x;j<m;j++)scanf("%d",&x),f[i][1<<j]=-x;
scanf("%d",&q);
for(int i=1,x,y,z,w;i<=q;i++){
scanf("%d%d",&x,&y),w=0;
while(y--)scanf("%d",&z),w|=(1<<(z-1));
g[w]+=x;
}
for(int i=0;i<m;i++)for(int j=0;j<lim;j++)if(j&(1<<i))g[j]+=g[j^(1<<i)];
dfs(1,0);
printf("%lld\n",f[1][lim-1]);
return 0;
}