Luogu P2515 软件安装【树形DP】【Floyd】

在这里插入图片描述



题目考点判断

  • 有依赖的背包问题

解决过程

  1. 判环
  2. 缩点
  3. 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]=nw[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]][yi]=dfs(c[x],yi);

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]][yi]+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;
}

猜你喜欢

转载自blog.csdn.net/Jackma_mayichao/article/details/108017297