P2014 [CTSC1997]选课
转化一下题意,给定一棵树, 求包含 0 0 0的结点一棵子树的点权和最大。
多叉树问题:
1.转二叉树。
2.树形背包。
int dfs(int u){
int sz=1;
for(int i=h[u];~i;i=e[i].nt){
int v=e[i].to;
int tmp=dfs(v);
sz+=tmp;
for(int j=sz;j>1;j--)
for(int k=0;k<=tmp;k++)
if(j-k>0) dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-k]);
}
return sz;
}
void solve(){
//think twice code once
scanf("%d%d",&n,&m);
mst(h,-1);
for(int i=1,x,y;i<=n;i++){
scanf("%d%d",&x,&y);
dp[i][1]=y;
add(x,i);
}
dfs(0);
printf("%d\n",dp[0][m+1]);
}
P3478 [POI2008]STA-Station
比较裸的转移题,先从1出发预处理除1的答案和sz[]数组。
然后进行转移
d p [ v ] = d p [ u ] + ( n − 2 s z [ v ] ) dp[v]=dp[u]+(n-2sz[v]) dp[v]=dp[u]+(n−2sz[v])
取个最值即可。
code
void dfs(int u,int fa,int d){
dp[1]+=d;sz[u]=1;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to;
if(v==fa) continue;
dfs(v,u,d+1);
sz[u]+=sz[v];
}
}
void dfs(int u,int fa){
if(ans<dp[u]) ans=dp[u],id=u;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to;
if(v==fa) continue;
dp[v]=dp[u]+(n-2*sz[v]);
dfs(v,u);
}
}
P3052 [USACO12MAR]Cows in a Skyscraper G
状压好题,需要维护一个sz[]数组,表示当前状态对应的最后一个组剩下的空间。
时间复杂度: O ( n 2 n ) O(n2^n) O(n2n)
void solve(){
scanf("%d%d",&n,&w);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
mst(f,0x3f);
f[0]=1,sz[0]=w;
int st=1<<n;
for(int i=0;i<st;i++)
for(int j=0;j<n;j++)
if(!(i>>j&1)){
if(sz[i]>=a[j]){
if(f[i|1<<j]>=f[i])
f[i|1<<j]=min(f[i|1<<j],f[i]),sz[i|1<<j]=max(sz[i|1<<j],sz[i]-a[j]);
}
else if(f[i|1<<j]>=f[i]+1){
f[i|1<<j]=min(f[i|1<<j],f[i]+1),sz[i|1<<j]=max(sz[i|1<<j],w-a[j]);
}
}
printf("%d\n",f[st-1]);
//think twice code once
}
P2679 [NOIP2015 提高组] 子串
需要维护一个前缀和,然后就是裸的dp,需要滚动数组优化
void solve(){
scanf("%d%d%d",&n,&m,&k1);
scanf("%s%s",a+1,b+1);
dp[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=m;j;j--)
for(int k=k1;k;k--){
if(a[i]==b[j]){
sum[j][k]=(sum[j-1][k]+dp[j-1][k-1])%mod;
dp[j][k]=(dp[j][k]+sum[j][k])%mod;
}
else sum[j][k]=0;
}
printf("%d\n",dp[m][k1]%mod);
//think twice code once
}