【DP】树形DP题目总结

来源:互联网 发布:淘宝商品怎么编辑 编辑:程序博客网 时间:2024/04/30 15:52


最近在研究树形DP,所以做了几道比较典型的树形DP的题目。大多数都是一些比较经典的题,大部分都用了多叉转二叉,题目也比较类似。感觉树形DP的模式都比较固定,基本都是先建树,然后dfs,方程也基本都是枚举左子树和右子树各自分配资源得到根的最大值,具体见题目吧。

 1、rqnoj30:愚蠢的矿工

#include<cstdio>#include<cstring>using namespace std;const int maxn = 1000 + 10;const int maxm = 100 + 10;struct tree{int l,r;tree(){l = r = -1;}}Tree[maxn];int n,m;int w[maxn];int f[maxn][maxm];bool map[maxn][maxn];void init(){freopen("rqnoj30.in","r",stdin);freopen("rqnoj30.out","w",stdout);}void readdata(){memset(map,false,sizeof(map));scanf("%d%d",&n,&m);for(int i = 1;i <= n;i++){scanf("%d",&w[i]);}for(int i = 1;i <= n;i++){int a,b;scanf("%d%d",&a,&b);map[a][b] = true;}}void maketree(int k){for(int i = 1;i <= n;i++){if(map[k][i]){if(Tree[k].l == -1){Tree[k].l = i;}else{int t = Tree[k].l;while(Tree[t].r != -1)t = Tree[t].r;Tree[t].r = i;}}}if(Tree[k].l != -1)maketree(Tree[k].l);if(Tree[k].r != -1)maketree(Tree[k].r);}int max(int a,int b){return a > b ? a : b;}int dfs(int d,int k){if(d == -1)return 0;if(f[d][k] != -1)return f[d][k];f[d][k] = dfs(Tree[d].r,k);for(int i = 0;i <= k - 1;i++){f[d][k] = max(dfs(Tree[d].l,i) + dfs(Tree[d].r,k-i-1) + w[d],f[d][k]);}return f[d][k];}void solve(){memset(f,-1,sizeof(f));for(int i = 1;i <= n;i++)f[i][0] = 0;maketree(0);printf("%d",dfs(0,m+1));}int main(){init();readdata();solve();return 0;}



 2、ural1018:二叉苹果树

#include<cstdio>#include<cstring>using namespace std;const int maxn = 100 + 10;struct tnode{int l,r;}tree[maxn];int map[maxn][maxn];int w[maxn];int f[maxn][maxn];int n,q;void init(){freopen("ural1018.in","r",stdin);freopen("ural1018.out","w",stdout);}void readdata(){memset(map,-1,sizeof(map));scanf("%d%d",&n,&q);for(int i = 1;i < n;i++){int l,r,w;scanf("%d%d%d",&l,&r,&w);map[l][r] = map[r][l] = w;}}void maketree(int v){for(int i = 1;i <= n;i++){if(map[v][i] >= 0){tree[v].l = i;w[i] = map[v][i];map[v][i] = map[i][v] = -1;maketree(i);break;}}for(int i = 1;i <= n;i++){if(map[v][i] >= 0){tree[v].r = i;w[i] = map[v][i];map[v][i] = map[i][v] = -1;maketree(i);break;}}}int max(int a,int b){return a > b ? a : b;}void dfs(int v,int k){if(k == 0)  f[v][k] = 0;else if(tree[v].l == 0 && tree[v].r == 0) {     f[v][k] = w[v]; } else { f[v][k] = 0; for(int i = 0;i < k;i++) { if(f[tree[v].l][i] == 0)dfs(tree[v].l,i); if(f[tree[v].r][k-i-1] == 0)dfs(tree[v].r,k-i-1); f[v][k] = max(f[v][k],f[tree[v].l][i]+f[tree[v].r][k-i-1] + w[v]); } }}void solve(){maketree(1);dfs(1,q+1);int ans = f[1][q+1];printf("%d",ans);}int main(){init();readdata();solve();return 0;}


 

 3、tyvj1051:选课

#include<cstdio>#include<cstring>using namespace std;const int maxn = 300 + 10;struct tree{int l,r;tree(){l = r = -1;}}Tree[maxn];bool map[maxn][maxn];int num[maxn];int f[maxn][maxn];int n,m;void init(){freopen("tyvj1051.in","r",stdin);freopen("tyvj1051.out","w",stdout);}void readdata(){memset(map,false,sizeof(map));scanf("%d%d",&n,&m);for(int i = 1;i <= n;i++){int t,w;scanf("%d%d",&t,&w);map[t][i] = true;num[i] = w;}}void maketree(int k){for(int i = 1;i <= n;i++){if(map[k][i]){if(Tree[k].l == -1){Tree[k].l = i;}else{int t = Tree[k].l;while(Tree[t].r != -1)t = Tree[t].r;Tree[t].r = i;}}}if(Tree[k].l != -1)maketree(Tree[k].l);if(Tree[k].r != -1)maketree(Tree[k].r);}int max(int a,int b){return a > b ? a : b;}int dfs(int t,int m){if(t == -1)return 0;if(f[t][m] != -1)return f[t][m];f[t][m] = dfs(Tree[t].r,m);for(int i = 0;i <= m - 1;i++){f[t][m] = max(dfs(Tree[t].l,i) + dfs(Tree[t].r,m-i-1) + num[t],f[t][m]);}return f[t][m];}void solve(){memset(f,-1,sizeof(f));for(int i = 1;i <= n;i++)f[i][0] = 0;maketree(0);printf("%d",dfs(0,m+1));}int main(){init();readdata();solve();return 0;}


 

 4、tyvj1052:没有上司的舞会

#include<cstdio>#include<cstring>using namespace std;const int maxn = 6000 + 10;struct tree{int l,r;tree(){l = r = -1;}}Tree[maxn];int root,n;int f[maxn][2];int w[maxn];bool map[maxn][maxn];bool flag[maxn];void init(){freopen("tyvj1052.in","r",stdin);freopen("tyvj1052.out","w",stdout);}void readdata(){memset(flag,true,sizeof(flag));memset(map,false,sizeof(map));scanf("%d",&n);for(int i = 1;i <= n;i++){scanf("%d",&w[i]);}for(int i = 1;i < n;i++){int l,k;scanf("%d%d",&l,&k);map[k][l] = true;flag[l] = false;}for(int i = 1;i <= n;i++){if(flag[i]){root = i;break;}}}void maketree(int k){for(int i = 1;i <= n;i++){if(map[k][i]){if(Tree[k].l == -1){Tree[k].l = i;}else{int t = Tree[k].l;while(Tree[t].r != -1)t = Tree[t].r;Tree[t].r = i;}}}if(Tree[k].l != -1)maketree(Tree[k].l);if(Tree[k].r != -1)maketree(Tree[k].r);}int max(int a,int b){return a > b ? a : b;}int dfs(int k,int s){if(f[k][s] != -1)return f[k][s];f[k][s] = 0;if(s == 1)f[k][s] = w[k];for(int i = Tree[k].l;i != -1;i = Tree[i].r){int com;if(s == 0){com = max(dfs(i,0),dfs(i,1));if(com >= 0)f[k][s] += com;}if(s == 1){com = dfs(i,0);if(com >= 0)f[k][s] += com;}}return f[k][s];}void solve(){memset(f,-1,sizeof(f));maketree(root);int ans = max(dfs(root,0),dfs(root,1));printf("%d",ans);}int main(){init();readdata();solve();return 0;}


 

 5、tyvj1513:小胖守皇宫

 这道题题意有点不好理解,每个节点有三种状态:第一种是在该节点放士兵;第二种是在该节点不放,但在它的儿子节点放了士兵;第三种是该节点不放,它被父亲节点影响。所以第一种情况可以由三种情况转移,第二种情况能由1,2种情况转移,第三种情况只能由第二种情况来转移。

#include<cstdio>#include<cstring>using namespace std;const int inf = 0x3ffff;const int maxn = 1500 + 10;const int maxm = 5;struct tree{int l,r;tree(){l = r = -1;}}Tree[maxn];int w[maxn];int f[maxn][maxm];int n,root;bool vis[maxn][maxm];bool map[maxn][maxn];bool flag[maxn];void init(){freopen("tyvj1513.in","r",stdin);freopen("tyvj1513.out","w",stdout);}void readdata(){memset(flag,false,sizeof(flag));memset(map,false,sizeof(map));scanf("%d",&n);for(int i = 1;i <= n;i++){int t1,m;scanf("%d",&t1);scanf("%d",&w[t1]);scanf("%d",&m);for(int j = 1;j <= m;j++){int t2;scanf("%d",&t2);map[t1][t2] = true;flag[t2] = true;}}for(int i = 1;i <= n;i++){if(flag[i] == false){root = i;break;}}}void maketree(int k){for(int i = 1;i <= n;i++){if(map[k][i]){if(Tree[k].l == -1){Tree[k].l = i;}else{int t = Tree[k].l;while(Tree[t].r != -1)t = Tree[t].r;Tree[t].r = i;}}}if(Tree[k].l != -1)maketree(Tree[k].l);if(Tree[k].r != -1)maketree(Tree[k].r);}int min(int a,int b){return a < b ? a : b;}int dfs(int k,int s){if(vis[k][s])return f[k][s];vis[k][s] = true;int sum = 0,temp = inf;for(int i = Tree[k].l;i != -1;i = Tree[i].r){if(s == 1){f[k][s] += min(dfs(i,1),min(dfs(i,2),dfs(i,3)));}if(s == 2){f[k][s] += min(dfs(i,1),dfs(i,2));if(f[i][1] - min(f[i][1],f[i][2]) < temp){temp = f[i][1] - min(f[i][1],f[i][2]);}}if(s == 3){f[k][s] += dfs(i,2);}}if(s == 1)f[k][s] += w[k];if(s == 2)f[k][s] += temp;return f[k][s];}void solve(){memset(vis,false,sizeof(vis));memset(f,0,sizeof(f));maketree(root);int ans = min(dfs(root,1),dfs(root,2));printf("%d",ans);}int main(){init();readdata();solve();return 0;}

The End...

原创粉丝点击