题目考点判断
- 有依赖的背包问题
解决过程
- 判环
- 缩点
- d f s dfs dfs 套 D P DP DP
1.判环
F l o y d Floyd Floyd 判环,如果 k k k 到 i i i 有一条路径且 i i i 到 j j j 有一条路径,就代表 i i i 和 j j j 是联通的。
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int k=1; k<=n; k++)
if(mapp[k][i]==1&&mapp[i][j]==1)
mapp[k][j]=1;
2. 缩点
情况1.
点 i i i 所在的环之前没有判断过,是新环。
那么,我们将这个新环放到数组最后,即新加一个点,
然后让这两个点的空间标记为负值 t m p w tmpw tmpw,且 t m p w + t m p n tmpw+tmpn tmpw+tmpn(新点的下标)等于原来的点数,
这样,我们就可以通过某个点的空间迅速找到他所在的新点。
像钥匙一样一一对应;
if(mapp[i][j]==1&&mapp[j][i]==1&&i!=j&&w[j]>0&&w[i]>0)
{
jsn++;
v[jsn]=v[i]+v[j]; //统计空间,价值
w[jsn]=w[i]+w[j];
jsw--;
w[i]=jsw,w[j]=jsw;
}
情况2.
点 i i i 所在的环之前已经判断过了,
是旧环(已合成新点),且 i i i 是环的一部分。
那么我们就把 i i i 也加到这个新点里面,
即体积,价值相加即可;
if(mapp[d[j]][j]==1&&mapp[j][d[j]]==1&&w[j]>0&&w[d[j]]<0)
{
w[n-w[d[j]]]+=w[j]; //将当前点加入它依赖点所在的环
v[n-w[d[j]]]+=v[j];
w[j]=w[d[j]];
}
情况3.
点 j j j 所在的环是旧环,
但是 i i i 不是环的一部分
(例如1依赖2,2依赖3,3依赖1。4也依赖1,那么,4所在的是个环,但4不属于环的一部分)
。
那么,把 j j j 的父亲转到新点上 d [ j ] = n − w [ d [ j ] ] d[j]= n-w[d[j]] d[j]=n−w[d[j]]。
if(w[j]>0&&w[d[j]]<0)
if((mapp[d[j]][j]==0&&mapp[j][d[j]]==1)||(mapp[d[j]][j]==1&&mapp[j][d[j]]==0))
d[j]=n-w[d[j]];
3.树形DP
以上缩点的工作做完之后,
剩下的就是一棵树。
就可以在这上面动规了:
先将其转换成一棵左孩子右兄弟的二叉树,
之后记忆化。
如果 i i i 的孩子不取 ,则:
f [ b [ x ] ] [ k ] = d f s ( b [ x ] , k ) f[b[x]][k]=dfs(b[x],k) f[b[x]][k]=dfs(b[x],k);
如果 i i i 的孩子取,则:
f [ c [ x ] ] [ y − i ] = d f s ( c [ x ] , y − i ) ; f[c[x]][y-i]=dfs(c[x],y-i); f[c[x]][y−i]=dfs(c[x],y−i);
f [ b [ x ] ] [ i ] = d f s ( b [ x ] , i ) ; f[b[x]][i]=dfs(b[x], i); f[b[x]][i]=dfs(b[x],i);
f [ x ] [ k ] = m a x ( f [ x ] [ k ] , v [ x ] + f [ c [ x ] ] [ y − i ] + f [ b [ x ] ] [ i ] ) ; f[x][k]=max(f[x][k],v[x]+f[c[x]][y-i]+f[b[x]][i]); f[x][k]=max(f[x][k],v[x]+f[c[x]][y−i]+f[b[x]][i]);
最后答案是 f [ c [ 0 ] ] [ m ] f[c[0]][m] f[c[0]][m] (从没有依赖的点开始)
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int N=1000010;
int w[N],v[N],mapp[2010][2010],d[N],b[N],f[2010][2010],c[N];
int n,m,x,jsn,jsw;
void floyd()
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
for(int k=1; k<=n; k++)
if(mapp[k][i]==1&&mapp[i][j]==1)
mapp[k][j]=1;
}
void sd()
{
jsn=n;
for(int i=1; i<=jsn; i++)
for(int j=1; j<=jsn; j++)
{
if(mapp[i][j]==1&&mapp[j][i]==1&&i!=j&&w[j]>0&&w[i]>0)
{
jsn++;
v[jsn]=v[i]+v[j];
w[jsn]=w[i]+w[j];
jsw--;
w[i]=jsw,w[j]=jsw;
}
if(mapp[d[j]][j]==1&&mapp[j][d[j]]==1&&w[j]>0&&w[d[j]]<0)
{
w[n-w[d[j]]]+=w[j];
v[n-w[d[j]]]+=v[j];
w[j]=w[d[j]];
}
if(w[j]>0&&w[d[j]]<0)
if((mapp[d[j]][j]==0&&mapp[j][d[j]]==1)||(mapp[d[j]][j]==1&&mapp[j][d[j]]==0))
d[j]=n-w[d[j]];
}
}
int dfs(int x,int k)
{
if(f[x][k]>0)
return f[x][k];
if(x==0||k==0)
return 0;
f[b[x]][k]=dfs(b[x],k);
f[x][k]=f[b[x]][k];
int y=k-w[x];
for(int i=0; i<=y; i++)
{
f[c[x]][y-i]=dfs(c[x],y-i);
f[b[x]][i]=dfs(b[x],i);
f[x][k]=max(f[x][k],v[x]+f[b[x]][i]+f[c[x]][y-i]);
}
return f[x][k];
}
int main()
{
cin>>n>>m;
for(int i=1; i<=n; i++)
scanf("%d",&w[i]);
for(int i=1; i<=n; i++)
scanf("%d",&v[i]);
for(int i=1; i<=n; i++)
{
scanf("%d",&x);
d[i]=x;
mapp[x][i]=1;
}
floyd();
sd();
for(int i=1; i<=jsn; i++)
if(w[i]>0)
{
b[i]=c[d[i]];
c[d[i]]=i;
}
cout<<dfs(c[0],m);
return 0;
}