csu 2014 summer training day 3 簡單樹形dp

FZU 2157php

題意:樹上的節點能夠打上0或1的標記,樹的權值由兩部分呢組成,點權和邊權,有00、0一、十、11四種組合的邊權,ios

問最小權值和。以1節點爲樹根ide

分析:dp[x][0]表示x標記0後的最小的權值,dp[x][1]同理spa

那麼每次能夠計算dp[x][0],dp[x][1];3d

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

具體看代碼。blog

用bfs寫的分層,深搜代碼更簡潔get

 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 2342string

題意:給定一顆boss樹,父親節點和孩子節點不能同時出現,問最多能選出多少節點it

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

dp[u][0]+=max(dp[v][1],dp[v][0]); dp[u][1]+=dp[v][0];
 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號節點開始,每次轉移,就能求出每一個節點的狀況了。
本身注意:向最長路徑上的點轉移時,長度是不會加一的。

具體看代碼:

 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就能搞定了

 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已作標記
  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
相關文章
相關標籤/搜索