poj3342 poj1463 poj3345 树形DP入门

poj3342 

View Code
 1 #include <map>
 2 #include <stdio.h>
 3 #include <vector>
 4 #include <string>
 5 #include <iostream>
 6 using namespace std;
 7 const int N=205;
 8 vector<int > V[N];
 9 map<string,int> M;
10 string child,father;
11 int dp[N][2];
12 bool ok[N][2];
13 int n,cnt;
14 void init(){
15     M.clear();
16     cnt=0;
17     for(int i=1;i<=n;i++){
18         V[i].clear();
19         dp[i][0]=0;
20         dp[i][1]=1;
21         ok[i][0]=ok[i][1]=1;
22     }
23 }
24 void input(){
25     cin>>father;
26     M[father]=++cnt;
27     for(int i=1;i<n;i++){
28         cin>>child;
29         if(M[child]==0){
30             M[child]=++cnt;
31         }
32         cin>>father;
33         if(M[father]==0){
34             M[father]=++cnt;
35         }
36         V[M[father]].push_back(M[child]);
37     }
38 }
39 //dp[i][0] = ∑max(dp[j][0], dp[j][1]) (j是i的儿子)
40 //dp[i][1] = 1 + ∑dp[j][0] (j是i的儿子)
41 void dfs(int u){
42     int i,v;
43     for(i=0;i<V[u].size();i++){
44         int v=V[u][i];
45         dfs(v);
46         dp[u][1]+=dp[v][0];
47         if(ok[v][0]==0) ok[u][1]=0;
48         if(dp[v][0]==dp[v][1]){
49             dp[u][0]+=dp[v][0];
50             ok[u][0]=0;
51         }else if(dp[v][0]>dp[v][1]){
52             dp[u][0]+=dp[v][0];
53             if(ok[v][0]==0) ok[u][0]=0;
54         }else if(dp[v][0]<dp[v][1]){
55             dp[u][0]+=dp[v][1];
56             if(ok[v][1]==0) ok[u][0]=0;
57         }
58     }
59     return ;
60 }
61 void solve(){
62     dfs(1);
63     if(dp[1][1]==dp[1][0]){
64         printf("%d No\n",dp[1][1]);
65     }else if(dp[1][1]>dp[1][0]){
66         printf("%d ",dp[1][1]);
67         if(ok[1][1]) puts("Yes");
68         else puts("No");
69     }else{
70         printf("%d ",dp[1][0]);
71         if(ok[1][0]) puts("Yes");
72         else puts("No");
73     }
74 }
75 int main(){
76     while(cin>>n&&n){
77         init();
78         input();
79         solve();
80     }
81     return 0;
82 }

poj1463

一开始理解成为只能在边上监视了,写好代码才意识到是点上监视,不过可以练习一下边上监视~

View Code
 1 #include <stdio.h>
 2 #include <vector>
 3 #include <string>
 4 #include <iostream>
 5 using namespace std;
 6 const int N=1505;
 7 bool in[N];
 8 int dp[N][2];
 9 int n,m,a,b;
10 vector<int> V[N];
11 int min(int a,int b){
12     return a<b?a:b;
13 }
14 void init(){
15     for(int i=0;i<n;i++){
16         V[i].clear();
17         in[i]=1;
18         dp[i][0]=0;
19         dp[i][1]=1;
20     }
21 }
22 /*
23 如果父节点无人看守,则孩子节点必须有人看守
24 如果父节点有人看守,则孩子节点可以有人看守也可以无人看守
25 */
26 void dfs(int u){
27     for(int i=0;i<V[u].size();i++){
28         int v=V[u][i];
29         dfs(v);
30         dp[u][1]+=min(dp[v][0],dp[v][1]);
31         dp[u][0]+=dp[v][1];
32     }
33     return ;
34 }
35 int main(){
36     int i;
37     while(scanf("%d",&n)!=EOF){
38         init();
39         for(i=0;i<n;i++){
40             scanf("%d:(%d)",&a,&m);
41             for(int j=0;j<m;j++){
42                 scanf("%d",&b);
43                 in[b]=0;
44                 V[a].push_back(b);
45             }
46         }
47         for(i=0;i<n;i++){
48             if(in[i]){
49                 dfs(i);
50                 break;
51             }
52         }
53         printf("%d\n",min(dp[i][0],dp[i][1]));
54     }
55     return 0;
56 }

poj3345

题意:有n个国家,要求至少买通m个,求最小代价,其中如果买通了一个国家,那么从属于它的国家也就视为被买通了,这些国家间的关系是一棵树。
思路:dp[i][j]表示以i为根的树中j个点花费的总价钱。

   dp[root][k] = min(dp[root][k],dp[child][j]+dp[root][k-j]);
   dp[root][num[root]] = weight[root];

View Code
  1 #include<iostream>
  2 #include<string>
  3 #include<map>
  4 #include<vector>
  5 #include<stdio.h>
  6 using namespace std;
  7 #define inf 0x3f3f3f3f
  8 #define N 205
  9 char str[N*100];
 10 char ch[N];
 11 int num[N],w[N];
 12 bool in[N];
 13 vector<int>V[N];
 14 int dp[N][N];
 15 int min(int a,int b){
 16     return a<b?a:b;
 17 }
 18 int n,m;
 19 void dfs(int u){
 20     int i,j,k,v;
 21     num[u]=1;
 22     dp[u][0]=0;
 23     for(i=0;i<V[u].size();i++){
 24         v=V[u][i];
 25         dfs(v);
 26         num[u]+=num[v];
 27         for(k=num[u];k>=0;k--){
 28             for(j=1;j<=k;j++)
 29                 dp[u][k]=min(dp[u][k],dp[v][j]+dp[u][k-j]);
 30         }
 31     }
 32     dp[u][num[u]]=w[u];
 33     return ;
 34 }
 35 bool check(char c){
 36     if(c>='0'&&c<='9') return 1;
 37     return 0;
 38 }
 39 int main(){
 40     int i,j,cnt,v;
 41     while(gets(ch)!=NULL){
 42         if(ch[0]=='#') break;
 43         //input
 44         map<string,int>M;
 45 
 46         cnt=v=0;
 47         for(i=0;check(ch[i]);i++){
 48             v=v*10+ch[i]-'0';
 49         }
 50         n=v;
 51 
 52         v=0;
 53         for(i++;check(ch[i]);i++){
 54             v=v*10+ch[i]-'0';
 55         }
 56         m=v;
 57 
 58         w[0]=0;
 59         for(i=0;i<=n;i++){
 60             V[i].clear();
 61             in[i]=1;
 62         }
 63 
 64         for(i=0;i<n;i++){
 65             gets(str);
 66             for(j=0;str[j]!=' ';j++);
 67             str[j]='\0';
 68             if(M[str]==0) M[str]=++cnt;
 69 
 70             v=0;
 71             for(j++;check(str[j]);j++){
 72                 v=v*10+str[j]-'0';
 73             }
 74             w[M[str]]=v;//!!!!!!!WA is w[cnt]=v;
 75 
 76             while(str[j]!='\0'){
 77                 int top=0;
 78                 for(j++;str[j]!='\0'&&str[j]!=' ';j++){
 79                     ch[top++]=str[j];
 80                 }ch[top]='\0';
 81 
 82                 if(M[ch]==0) M[ch]=++cnt;
 83                 V[M[str]].push_back(M[ch]);
 84                 in[M[ch]]=0;
 85             }
 86         }
 87         //solve
 88         for(i=1;i<=n;i++){
 89             if(in[i])
 90                 V[0].push_back(i);
 91         }
 92         for(i=0;i<=n;i++)
 93             for(j=0;j<=n;j++)
 94                 dp[i][j]=inf;
 95         dfs(0);
 96         int ans=dp[0][m];
 97         for(i=m;i<=n;i++){
 98             if(dp[0][i]<ans)
 99                 ans=dp[0][i];
100         }
101         printf("%d\n",ans);
102     }
103     return 0;
104 }

 

 

转载于:https://www.cnblogs.com/-sunshine/archive/2013/01/19/2867204.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值