码迷,mamicode.com
首页 > 其他好文 > 详细

csu 2014 summer training day 3 简单树形dp

时间:2014-07-22 00:09:35      阅读:371      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   os   strong   

FZU 2157

题意:树上的节点可以打上0或1的标记,树的权值由两部分呢组成,点权和边权,有00、01、10、11四种组合的边权,

问最小权值和。以1节点为树根

分析:dp[x][0]表示x标记0后的最小的权值,dp[x][1]同理

那么每次可以计算dp[x][0],dp[x][1];

例如dp[x][1]=min(dp[son][0]+lab[0][1]+val[1],dp[son][1]+bal[1][1]+val[1]);

具体看代码。

用bfs写的分层,深搜代码更简洁

bubuko.com,布布扣
 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <vector>
 5 #include <map>
 6 #include <string>
 7 #include <queue>
 8 #define LL long long
 9 #define maxn 201000
10 using namespace std;
11 //map存储标号
12 //边读边记录边的关系
13 //bfs分层记录每层节点
14 //从底层向上层dp
15 int la[maxn][2];
16 int bel[maxn][2][2];
17 vector<int> G[maxn];
18 vector<int> Ceil[maxn];
19 int n,cnum;//点数,分层数
20 void init(){
21     for(int i=0;i<maxn;i++) G[i].clear();
22     for(int i=0;i<maxn;i++) Ceil[i].clear();
23     cnum=0;
24     return ;
25 }
26 typedef pair<int,int>PAIR;
27 bool vis[maxn];
28 void Bfs(){
29     queue<PAIR> Q ;
30     Q.push(make_pair(1,1));
31     memset(vis,0,sizeof(vis));
32     vis[1]=true;
33     while(!Q.empty()){
34         PAIR New=Q.front();
35         Q.pop();
36         int u=New.first;
37         int st=New.second;
38         Ceil[st].push_back(u);
39         cnum=max(cnum,st);
40         for(int i=0;i<G[u].size();i++){
41             int v=G[u][i];
42             if (vis[v]) continue;
43             Q.push(make_pair(v,st+1));
44             vis[v]=true;
45         }
46     }
47     return;
48 }
49 LL dp[maxn][2];//0表示不选择i节点,1表示选择i节点
50 void solve(){
51     memset(dp,0,sizeof(dp));
52     for(int i=0;i<Ceil[cnum].size();i++){
53         int u=Ceil[cnum][i];
54         dp[u][0]=(LL)la[u][0];dp[u][1]=(LL)la[u][1];
55     }
56     for(int i=cnum-1;i>=1;i--){
57         for(int j=0;j<Ceil[i].size();j++){
58             int u=Ceil[i][j];
59             for(int k=0;k<G[u].size();k++){
60                 int v=G[u][k];
61                 dp[u][0]+=min(dp[v][0]+bel[v][0][0],dp[v][1]+bel[v][0][1]);
62                 dp[u][1]+=min(dp[v][0]+bel[v][1][0],dp[v][1]+bel[v][1][1]);
63             }
64             dp[u][1]+=(LL)la[u][1];
65             dp[u][0]+=(LL)la[u][0];
66 //            cout<<"u="<<u<<","<<"1:"<<dp[u][1]<<endl;
67 //            cout<<"u="<<u<<","<<"0:"<<dp[u][0]<<endl;
68         }
69     }
70     printf("%I64d\n",min(dp[1][1],dp[1][0]));
71     return ;
72 }
73 int t;
74 int main(){
75     scanf("%d",&t);
76     while(t--){
77         scanf("%d",&n);
78         init();
79         for(int i=1;i<=n;i++){
80             scanf("%d",&la[i][0]);
81         }
82         for(int i=1;i<=n;i++){
83             scanf("%d",&la[i][1]);
84         }
85         int u,v,a,b,c,d;
86         for(int i=1;i<=n-1;i++){
87             scanf("%d%d%d%d%d%d",&u,&v,&a,&b,&c,&d);
88             bel[v][0][0]=a;
89             bel[v][0][1]=b;
90             bel[v][1][0]=c;
91             bel[v][1][1]=d;
92             G[u].push_back(v);
93         }
94         Bfs();//分层
95         solve();
96     }
97     return 0;
98 }
View Code

 

POJ 2342

题意:给定一颗boss树,父亲节点和孩子节点不能同时出现,问最多能选出多少节点

分析:dp[x][0]:x不出现,dp[x][1]:x出现

dp[u][0]+=max(dp[v][1],dp[v][0]);
dp[u][1]+=dp[v][0];
bubuko.com,布布扣
 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <vector>
 5 #include <map>
 6 #include <string>
 7 #include <queue>
 8 #define LL long long
 9 #define maxn 201000
10 using namespace std;
11 //map存储标号
12 //边读边记录边的关系
13 //bfs分层记录每层节点
14 //从底层向上层dp
15 int la[maxn][2];
16 int bel[maxn][2][2];
17 vector<int> G[maxn];
18 vector<int> Ceil[maxn];
19 int n,cnum;//点数,分层数
20 void init(){
21     for(int i=0;i<maxn;i++) G[i].clear();
22     for(int i=0;i<maxn;i++) Ceil[i].clear();
23     cnum=0;
24     return ;
25 }
26 typedef pair<int,int>PAIR;
27 bool vis[maxn];
28 void Bfs(){
29     queue<PAIR> Q ;
30     Q.push(make_pair(1,1));
31     memset(vis,0,sizeof(vis));
32     vis[1]=true;
33     while(!Q.empty()){
34         PAIR New=Q.front();
35         Q.pop();
36         int u=New.first;
37         int st=New.second;
38         Ceil[st].push_back(u);
39         cnum=max(cnum,st);
40         for(int i=0;i<G[u].size();i++){
41             int v=G[u][i];
42             if (vis[v]) continue;
43             Q.push(make_pair(v,st+1));
44             vis[v]=true;
45         }
46     }
47     return;
48 }
49 LL dp[maxn][2];//0表示不选择i节点,1表示选择i节点
50 void solve(){
51     memset(dp,0,sizeof(dp));
52     for(int i=0;i<Ceil[cnum].size();i++){
53         int u=Ceil[cnum][i];
54         dp[u][0]=(LL)la[u][0];dp[u][1]=(LL)la[u][1];
55     }
56     for(int i=cnum-1;i>=1;i--){
57         for(int j=0;j<Ceil[i].size();j++){
58             int u=Ceil[i][j];
59             for(int k=0;k<G[u].size();k++){
60                 int v=G[u][k];
61                 dp[u][0]+=min(dp[v][0]+bel[v][0][0],dp[v][1]+bel[v][0][1]);
62                 dp[u][1]+=min(dp[v][0]+bel[v][1][0],dp[v][1]+bel[v][1][1]);
63             }
64             dp[u][1]+=(LL)la[u][1];
65             dp[u][0]+=(LL)la[u][0];
66 //            cout<<"u="<<u<<","<<"1:"<<dp[u][1]<<endl;
67 //            cout<<"u="<<u<<","<<"0:"<<dp[u][0]<<endl;
68         }
69     }
70     printf("%I64d\n",min(dp[1][1],dp[1][0]));
71     return ;
72 }
73 int t;
74 int main(){
75     scanf("%d",&t);
76     while(t--){
77         scanf("%d",&n);
78         init();
79         for(int i=1;i<=n;i++){
80             scanf("%d",&la[i][0]);
81         }
82         for(int i=1;i<=n;i++){
83             scanf("%d",&la[i][1]);
84         }
85         int u,v,a,b,c,d;
86         for(int i=1;i<=n-1;i++){
87             scanf("%d%d%d%d%d%d",&u,&v,&a,&b,&c,&d);
88             bel[v][0][0]=a;
89             bel[v][0][1]=b;
90             bel[v][1][0]=c;
91             bel[v][1][1]=d;
92             G[u].push_back(v);
93         }
94         Bfs();//分层
95         solve();
96     }
97     return 0;
98 }
View Code

 

HDU 2196

题意:给定一棵树,分别求1..N分别作为树根时,最长的树枝长是多少?

分析:两遍dfs,第一遍处理出(以1为根节点):

int max1[maxn];//以1为根,i节点的最长路径
int max2[maxn];//以1为根,i节点的次长路径,保证最长边的下一点不在这条路径上

记录下相应的下一个节点的编号:

int max1id[maxn];
int max2id[maxn];

第二遍处理出:转移节点后每个点作为根节点点的max1和max2,dfs搜索更新,这样从1号节点开始,每次转移,就能求出每个节点的情况了。
自己注意:向最长路径上的点转移时,长度是不会加一的。

具体看代码:

bubuko.com,布布扣
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #define maxn 10100
 6 using namespace std;
 7 
 8 vector<int>G[maxn];
 9 vector<int>len[maxn];
10 int N;
11 int max1[maxn];//以1为根,i节点的最长路径
12 int max2[maxn];//以1为根,i节点的次长路径,保证最长边的下一点不在这条路径上
13 int max1id[maxn];
14 int max2id[maxn];
15 void init(){
16     for(int i=0;i<=N;i++){
17         G[i].clear();
18         len[i].clear();
19     }
20 }
21 bool vis[maxn];
22 void dfs1(int u,int fa){
23     max1[u]=0;
24     max2[u]=0;
25     for(int i=0;i<G[u].size();i++){
26         int v=G[u][i];
27         if (v==fa) continue;
28         dfs1(v,u);
29         if (max1[v]+len[u][i]>max2[u]){//这个方法真机智啊
30             max2[u]=max1[v]+len[u][i];
31             max2id[u]=v;
32         }
33         if (max1[u]<max2[u]){
34             swap(max1[u],max2[u]);
35             swap(max1id[u],max2id[u]);
36         }
37     }
38     return;
39 }
40 void dfs2(int u,int fa){
41     for(int i=0;i<G[u].size();i++){
42         int v=G[u][i];
43         if (v==fa) continue;
44         //用u去更新v
45         if (max1id[u]==v){
46             if (max2[v]<max2[u]+len[u][i]){
47                 max2[v]=max2[u]+len[u][i];
48                 max2id[v]=u;
49             }
50         }else {
51             if (max2[v]<max1[u]+len[u][i]){
52                 max2[v]=max1[u]+len[u][i];
53                 max2id[v]=u;
54             }
55         }
56         if (max2[v]>max1[v]){
57             swap(max2[v],max1[v]);
58             swap(max2id[v],max1id[v]);
59         }
60         dfs2(v,u);
61     }
62     return ;
63 }
64 int main()
65 {
66     while(~scanf("%d",&N)){
67         init();
68         int v,c;
69         for(int i=2;i<=N;i++){
70             scanf("%d%d",&v,&c);
71             G[i].push_back(v);
72             G[v].push_back(i);
73             len[i].push_back(c);
74             len[v].push_back(c);
75         }
76         dfs1(1,-1);
77         dfs2(1,-1);
78         for(int i=1;i<=N;i++) printf("%d\n",max1[i]);
79     }
80 
81     return 0;
82 }
View Code
 

POJ 4045

 

题意:这个题大致意思是给你一颗树,让你求一点,使该点到其余各点的距离之和最小。如果这样的点有多个,则按升序依次输出。

分析:cunt[x]记录以x为根的子树中节点的个数

        dp[x]记录以x为根时,x到所有节点的距离之和

        第一遍dfs处理这两个

        又是一道根节点转移的题目

vsum=sum-cunt[v]-1+(N-cunt[v]-2)+1;
sum是以当前节点u为根时的所求值,vsum是将根转移到v节点上,所以v节点形成的子树整体上移,深度都减少了1,而其他节点深度都增加了1,这个在纸上画一画就明白了。
所以dfs就能搞定了

bubuko.com,布布扣
 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdio.h>
 4 #include <vector>
 5 #include <algorithm>
 6 #include <map>
 7 #include <string>
 8 #include <queue>
 9 #define LL long long
10 #define maxn 51000
11 using namespace std;
12 vector<int>G[maxn];
13 LL dp[maxn];
14 LL cunt[maxn];
15 bool vis[maxn];
16 LL Min;
17 int cnt=0;
18 int ans[maxn];
19 void init(){
20     for(int i=0;i<maxn;i++) G[i].clear();
21     memset(dp,0,sizeof(dp));
22     memset(cunt,0,sizeof(cunt));
23 }
24 LL dfs1(int u){
25     LL ans=0;
26     for(int i=0;i<G[u].size();i++){
27         int v=G[u][i];
28         if (vis[v]) continue;
29         vis[v]=true;
30         ans+=dfs1(v)+1;
31     }
32     return cunt[u]=ans;
33 }
34 LL dfs2(int u){
35     LL ans=0;
36     for(int i=0;i<G[u].size();i++){
37         int v=G[u][i];
38         if (vis[v]) continue;
39         vis[v]=true;
40         ans+=dfs2(v)+1+cunt[v];
41     }
42     return dp[u]=ans;
43 }
44 LL sum1,cunt1;
45 LL N,I,R;
46 void dfs3(int u,LL sum){
47     LL vsum=0;
48     for(int i=0;i<G[u].size();i++){
49         int v=G[u][i];
50         if (vis[v]) continue;
51         vsum=sum-cunt[v]-1+(N-cunt[v]-2)+1;
52         if (vsum==Min) ans[cnt++]=v;
53         if (vsum<Min) {
54             cnt=0;
55             ans[cnt++]=v;
56             Min=vsum;
57         }
58         LL cu=cunt[u],cv=cunt[v];
59         cunt[v]=N-1;
60         cunt[u]=N-cv-2;
61         vis[v]=true;
62         dfs3(v,vsum);
63         cunt[v]=cv,cunt[u]=cu;
64     }
65     return ;
66 }
67 int t;
68 int main(){
69     scanf("%d",&t);
70     while(t--){
71         init();
72         scanf("%lld%lld%lld",&N,&I,&R);
73         for(int i=1;i<=N-1;i++){
74             int u,v;
75             scanf("%d%d",&u,&v);
76             G[u].push_back(v);
77             G[v].push_back(u);
78         }
79         memset(vis,0,sizeof(vis));vis[1]=true;
80         cunt1=dfs1(1);
81         memset(vis,0,sizeof(vis));vis[1]=true;
82         sum1=dfs2(1);
83         Min=sum1;cnt=0;
84         ans[cnt++]=1;
85         memset(vis,0,sizeof(vis));vis[1]=true;
86         dfs3(1,sum1);
87         sort(ans,ans+cnt);
88         printf("%lld\n",Min*I*I*R);
89         for(int i=0;i<cnt;i++){
90             if (i==cnt-1) printf("%d\n",ans[i]);
91             else printf("%d ",ans[i]);
92         }
93         printf("\n");
94     }
95     return 0;
96 }
View Code

POJ 3342

题意:和第二题很想,父亲和孩子不能都选择,但是要判断选择的方案是否唯一

分析:讨论一下新增部分,

新增dup[x][0]、dup[x][1]分别表示选与不选是否唯一

memset(dup,0,sizeof(dup));//1表示确定,0不确定
其中v就是son节点
if ((dp[v][0]>dp[v][1]&&dup[v][0]==0)||(dup[v][1]>dup[v][0]&&dup[v][1]==0)||(dp[v][1]==dp[v][0]))
                    dup[u][0]=0;
if (dup[v][0]==0) dup[u][1]=0;
我们判断dp[v][0]和dp[v][1]哪个大,这样dup[v][0]的状态就延续上去了(当然是必然选择的那个状态延续),当然若dp[v][1]==dp[v][0],dup就是0了
dup需要赋初值1已做标记
bubuko.com,布布扣
  1 #include <iostream>
  2 #include <string.h>
  3 #include <stdio.h>
  4 #include <vector>
  5 #include <map>
  6 #include <string>
  7 #include <queue>
  8 #define maxn 310
  9 using namespace std;
 10 //map存储标号
 11 //边读边记录边的关系
 12 //bfs分层记录每层节点
 13 //从底层向上层dp
 14 vector<int> G[maxn];
 15 vector<int> Ceil[maxn];
 16 map<string,int>Mp;
 17 int n,cnum,cnt;//人数,分层数
 18 void init(){
 19     for(int i=0;i<maxn;i++) G[i].clear();
 20     for(int i=0;i<maxn;i++) Ceil[i].clear();
 21     cnum=0;cnt=0;
 22     Mp.clear();
 23     return ;
 24 }
 25 typedef pair<int,int>PAIR;
 26 bool vis[maxn];
 27 void Bfs(){
 28     queue<PAIR> Q ;
 29     Q.push(make_pair(1,1));
 30     memset(vis,0,sizeof(vis));
 31     vis[1]=true;
 32     while(!Q.empty()){
 33         PAIR New=Q.front();
 34         Q.pop();
 35         int u=New.first;
 36         int st=New.second;
 37         Ceil[st].push_back(u);
 38         cnum=max(cnum,st);
 39         for(int i=0;i<G[u].size();i++){
 40             int v=G[u][i];
 41             if (vis[v]) continue;
 42             Q.push(make_pair(v,st+1));
 43             vis[v]=true;
 44         }
 45     }
 46     return;
 47 }
 48 int dp[maxn][2];//0表示不选择i节点,1表示选择i节点
 49 int dup[maxn][2];
 50 void solve(){
 51     memset(dup,0,sizeof(dup));//1表示确定,0不确定
 52     memset(dp,0,sizeof(dp));
 53     for(int i=0;i<Ceil[cnum].size();i++){
 54         int u=Ceil[cnum][i];
 55         dp[u][0]=0;dp[u][1]=1;
 56         dup[u][0]=dup[u][1]=1;
 57     }
 58     for(int i=cnum-1;i>=1;i--){
 59         for(int j=0;j<Ceil[i].size();j++){
 60             int u=Ceil[i][j];
 61             dup[u][0]=dup[u][1]=1;
 62             for(int k=0;k<G[u].size();k++){
 63                 int v=G[u][k];
 64                 dp[u][0]+=max(dp[v][0],dp[v][1]);
 65                 dp[u][1]+=dp[v][0];
 66                 if ((dp[v][0]>dp[v][1]&&dup[v][0]==0)||(dup[v][1]>dup[v][0]&&dup[v][1]==0)||(dp[v][1]==dp[v][0]))
 67                     dup[u][0]=0;
 68                 if (dup[v][0]==0) dup[u][1]=0;
 69             }
 70             dp[u][1]++;
 71         }
 72     }
 73     if (dp[1][0]==dp[1][1]){
 74         printf("%d No\n",dp[1][0]);
 75     }
 76     if (dp[1][0]>dp[1][1]){
 77         printf("%d ",dp[1][0]);
 78         if (dup[1][0]) puts("Yes");else puts("No");
 79     }
 80     if (dp[1][1]>dp[1][0]){
 81         printf("%d ",dp[1][1]);
 82         if (dup[1][1]) puts("Yes");else puts("No");
 83     }
 84     return;
 85 }
 86 int main(){
 87     string s;
 88     char s1[55],s2[55];
 89     while(~scanf("%d",&n)&&n){
 90         init();
 91         scanf("%s",s1);
 92         Mp[s=s1]=++cnt;
 93         for(int i=1;i<n;i++){
 94             scanf("%s",s1);scanf("%s",s2);
 95             int u,v;
 96             if (Mp.count(s=s1)) u=Mp[s=s1];
 97             else u=Mp[s=s1]=++cnt;
 98             if (Mp.count(s=s2)) v=Mp[s=s2];
 99             else v=Mp[s=s2]=++cnt;
100             G[v].push_back(u);
101         }
102         Bfs();//分层
103         solve();
104     }
105     return 0;
106 }
View Code

 

csu 2014 summer training day 3 简单树形dp,布布扣,bubuko.com

csu 2014 summer training day 3 简单树形dp

标签:style   blog   http   color   os   strong   

原文地址:http://www.cnblogs.com/little-w/p/3858654.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!