树型dp入门小节

来源:互联网 发布:sqlserver密码策略 编辑:程序博客网 时间:2024/06/08 03:00

做了几道树型dp的入门题,稍微总结一下


hdu1520:http://acm.hdu.edu.cn/showproblem.php?pid=1520(入门)

题意:每个人有一些活跃值,员工和上司关系组成一棵树,树上如果父亲来了,向下相邻的儿子就来不了,问最大的活跃值总和(题意略坑,可能不止一棵树)


用dp[i][0]表示当前点没来的最大值,dp[i][1]表示当前点来了的最大值,则dfs时有状态转移方程:

dp[u][0] += max(dp[v][1],dp[v][0])

dp[u][1] += dp[v][0]

其中u为父亲,v为相邻儿子,根可能有多个,枚举所有没有父亲的节点dfs就好了

#include<bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define For(a,b,c) for(int a = b;a <= c;a++)using namespace std;typedef long long ll;const int maxn = 6005;const int INF = 0x3f3f3f3f;const double eps = 1e-8;struct ppp{int v,nex;}e[maxn * 20];int tole;int N;int ru[maxn];int dp[maxn][2];int head[maxn];void make_edge(int u,int v){e[tole].v = v;e[tole].nex = head[u];head[u] = tole++;}int dfs(int u,int pre){for(int i = head[u];~i;i = e[i].nex){int v = e[i].v;if(v == pre)continue;dfs(v,u);dp[u][1] += dp[v][0];dp[u][0] += max(dp[v][0],dp[v][1]);}return max(dp[u][0],dp[u][1]);}int main(){while(~scanf("%d",&N)){if(N == 0)break;mem(head,-1);tole = 0;mem(dp,0);mem(ru,0);for(int i = 1;i <= N;i++)scanf("%d",&dp[i][1]);for(int i = 1;1;i++){int a,b;scanf("%d%d",&a,&b);if(a == 0 && b == 0)break;make_edge(b,a);make_edge(a,b);ru[a]++;}int ans = 0 ;for(int i = 1;i <= N;i++)if(!ru[i]){ans += dfs(i,-1);}cout<<ans<<endl;}}



hdu1561:http://acm.hdu.edu.cn/showproblem.php?pid=1561

题意中文,不多解释了

想法:要攻占某个城堡则其父亲节点的城堡一定要被攻占,列出状态方程为

dp[i][j],表示为第i个节点攻占了j个城堡的最大值(包括自己和儿子),那么显然对与每个节点这相当于一个背包问题

dp[u][j] = max(dp[u][j],dp[v][k] + dp[u][j - k])j从M枚举到1,k从0枚举到j(就是背包的做法),注意到0是虚构点,枚举的时候要去掉包括占领0号城堡的情况

#include<bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define For(a,b,c) for(int a = b;a <= c;a++)using namespace std;typedef long long ll;const int maxn = 202;const int INF = 0x3f3f3f3f;const double eps = 1e-8;struct ppp{    int v,nex;}e[maxn * 1000];int head[maxn],tole;void make_edge(int u,int v){    e[tole].v = v;e[tole].nex = head[u];head[u] = tole++;}int dp[maxn][maxn];int N,M;void dfs(int u,int fa){    for(int i = head[u];~i;i = e[i].nex)    {        int v = e[i].v;        if(v == fa)continue;        dfs(v,u);        for(int j = M;j >= 0;j--)        {            int temp = j;            if(u == 0)            temp = j + 1;            for(int k = 0;k < temp;k++)            {                dp[u][j] = max(dp[u][j],dp[v][k] + dp[u][j - k]);            }        }    }}int main(){    while(scanf("%d%d",&N,&M))    {        if(N == 0 && M == 0)break;        mem(dp,0);        tole = 0;        mem(head,-1);        for(int i = 1;i <= N;i++)        {            int a;            scanf("%d%d",&a,&dp[i][1]);            make_edge(i,a);            make_edge(a,i);        }        dfs(0,-1);        printf("%d\n",dp[0][M]);    }



hdu1011:http://acm.hdu.edu.cn/showproblem.php?pid=1011

到下一个房间必须消灭当前房间,dp时类似背包的做法。

#include<bits/stdc++.h>#define mem(a,b) memset(a,b,sizeof(a))#define For(a,b,c) for(int a = b;a <= c;a++)using namespace std;typedef long long ll;const int maxn = 102;const int INF = 0x3f3f3f3f;const double eps = 1e-8;struct ppp{    int v,nex;}e[maxn * 1000];int head[maxn],tole;void make_edge(int u,int v){    e[tole].v = v;e[tole].nex = head[u];head[u] = tole++;}int dp[maxn][maxn];int N,M;int ori[maxn];//ori[i]为消灭玩第i个房间所需要的troopvoid dfs(int u,int fa){    for(int i = head[u];~i;i = e[i].nex)    {        int v = e[i].v;        if(v == fa)continue;        dfs(v,u);        for(int k = M;k >= ori[u];k--)//要进入下一个房间这个房间必须消灭,所以k>=ori[u]            for(int j = 1;j <= k - ori[u];j++)//背包做法,dp                dp[u][k] = max(dp[u][k],dp[v][j] + dp[u][k - j]);    }}int main(){    while(~scanf("%d%d",&N,&M))    {        if(N == -1 && M == -1)break;        tole=  0;        mem(dp,0);        mem(head,-1);        for(int i = 1;i <= N;i++)        {            int a,b;            scanf("%d%d",&a,&b);            a = (a + 19) / 20;            dp[i][a] = b;            for(int j = a;j <= M;j++)//这个初始化一定要加                dp[i][j] = b;            ori[i] = a;        }        for(int i = 1;i < N;i++)        {            int a,b;            scanf("%d%d",&a,&b);            make_edge(a,b);            make_edge(b,a);        }        if(!M)//这个特判貌似必须要加....不然是WA...        {            printf("0\n");continue;        }        dfs(1,-1);        int ans = -1;        for(int i = 0;i <= M;i++)            ans = max(dp[1][i],ans);        printf("%d\n",ans);    }}


0 0
原创粉丝点击