hdu-1561(树形dp)_子节点


hdu-1561(树形dp)_子节点_02


讲解:

这是一道简单的树形dp以第二组样例为例

(i代表次序,a代表攻克a,需先攻克i,w代表权值)

i

a

w

1

2

2

2

0

1

3

0

4

4

2

1

5

7

1

6

7

6

7

2

2

这里用​​vector​​建图

hdu-1561(树形dp)_i++_03


用​​vector​​确立点与点之间的关系后便为上图

网上许多代码用链式前向星,会快一点,但是​​vector​​会减少编码复杂度,这个图再加一个节点就成了一个树,所以在加一个根节点,这个根节点是虚拟的以0为根节点

hdu-1561(树形dp)_i++_04


可以得到转移方程​​dp[i][j]=max(dp[i][j],dp[i][k]+dp[x][j-k])​​​,代表含义:以​​i​​​为节点,​​j​​​为攻克城堡数量,比较以i为节点攻克​​j​​​个城堡的价值和以​​i​​​为节点攻克​​k​​​个城堡的价值+以​​i​​​节点的子节点攻克​​j-k​​个城堡的价值

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 1005
using namespace std;
int dp[maxn][maxn];
int vis[maxn];
vector<int>vec[maxn];
int n,m;
void input()
{
int u,w;
for(int v=1; v<=n; v++) //n次询问
{
scanf("%d %d",&u,&w);
vec[u].push_back(v);
dp[v][1]=w;//攻破v后所获得的价值
}
}
void dfs(int x)//以x为节点向下搜索
{
vis[x]=1;
int v=x;
for(int i=0; i<vec[x].size(); i++)
{
v=vec[x][i];
if(!vis[v])
{
dfs(v);
}

for(int j=m+1; j>=2; j--) //攻破m个城堡
{
for(int k=1; k<j; k++) //取k个点
{
if(dp[v][j-k]!=-1&&dp[x][k]!=-1)
{
dp[x][j]=max(dp[x][j],dp[v][j-k]+dp[x][k]);
}
}
}
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
if(n==0&&m==0)
break;
memset(vis,0,sizeof(vis));
memset(dp,-1,sizeof(dp));
memset(vec,0,sizeof(vec));

for(int i=0; i<=n; i++)
dp[i][0]=0;
dp[0][1]=0;
input();
dfs(0);
printf("%d\n",dp[0][m+1]);

}
}