软件安装
解题思路
1:这题可能形成环
所以要缩点,用强连通分量
void sd()//缩点
{
o=n;
for(int i=1;i<=o;i++)
for(int j=1;j<=o;j++)
{
if(a[i][j]==1&&a[j][i]==1&&w[i]>0&&w[j]>0&&i!=j)
{
o++;
w[o]=w[i]+w[j];
v[o]=v[i]+v[j];
w[i]=w[j]=--o1;
}
if(a[d[j]][j]==1&&a[j][d[j]]==1&&w[d[j]]<0&&w[j]>0)
{
w[n-w[d[j]]]+=w[j];
v[n-w[d[j]]]+=v[j];
w[j]=w[d[j]];
}
if(w[d[j]]<0&&w[j]>0)
if((a[d[j]][j]==1&&a[j][d[j]]==0)||(a[d[j]][j]==0&&a[j][d[j]]==1))
d[j]=n-w[d[j]];
}
}
2:状态转移
我们分析x和它儿子和它爸爸的关系
它要在它爸爸选了之后才能选,所以它爸爸的值可以传承到它身上,当作不选它
我们类似完全背包的做法,枚举当前还剩的空间
f[c[x]][k-w[x]-i]=dp(c[x], k-w[x]-i);//枚举儿子
f[b[x]][i]=dp(b[x], i);//父亲的传承
f[x][k]=max(f[x][k],v[x]+f[c[x]][k-w[x]-i]+f[b[x]][i]);
最后呈上AC代码
AC代码
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,o,o1,w[1005],v[1005],d[1005],b[1005],c[1005],a[1005][1005],f[1005][1005];
void sd()//缩点
{
o=n;
for(int i=1;i<=o;i++)
for(int j=1;j<=o;j++)
{
if(a[i][j]==1&&a[j][i]==1&&w[i]>0&&w[j]>0&&i!=j)
{
o++;
w[o]=w[i]+w[j];
v[o]=v[i]+v[j];
w[i]=w[j]=--o1;
}
if(a[d[j]][j]==1&&a[j][d[j]]==1&&w[d[j]]<0&&w[j]>0)
{
w[n-w[d[j]]]+=w[j];
v[n-w[d[j]]]+=v[j];
w[j]=w[d[j]];
}
if(w[d[j]]<0&&w[j]>0)
if((a[d[j]][j]==1&&a[j][d[j]]==0)||(a[d[j]][j]==0&&a[j][d[j]]==1))
d[j]=n-w[d[j]];
}
}
int dp(int x,int k)
{
if(f[x][k]>0)return f[x][k];
if(x==0||k<=0)return 0;
f[b[x]][k]=dp(b[x], k);
f[x][k]=f[b[x]][k];
for(int i=0;i<=k-w[x];i++)
{
f[c[x]][k-w[x]-i]=dp(c[x], k-w[x]-i);//枚举儿子
f[b[x]][i]=dp(b[x], i);//父亲的传承
f[x][k]=max(f[x][k],v[x]+f[c[x]][k-w[x]-i]+f[b[x]][i]);
}
return f[x][k];
}
int main()
{
cin>>n>>m;//输入
for(int i=1;i<=n;i++)cin>>w[i];
for(int i=1;i<=n;i++)cin>>v[i];
for(int i=1;i<=n;i++)
{
cin>>d[i];
a[d[i]][i]=1;//邻接矩阵
}
for(int i=1;i<=n;i++)//floyed 来缩点
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
if(a[k][i]==1&&a[i][j]==1)
a[k][j]=1;
sd();//缩点
for(int i=1;i<=o;i++)//预处理
if(w[i]>0)
{
b[i]=c[d[i]];
c[d[i]]=i;
}
cout<<dp(c[0],m); //dp输出
}