zoukankan      html  css  js  c++  java
  • 树形DP

    树形DP小结:

                  1:n个点,n-1条边;

                  2:无环,根结点可由子结点推出;

                  3:一般的状态都是以某一个结点为根的子树代表什么,

                         然后通过递归,由一个一个子结点推出根结点状态;

                         递推关系:Dp[i][j]=max(dp[i][j],dp[i][k]+dp[son[i][j-k]);

                         说明递推的含义,首先dp[i][j]的第一个值肯定从dp[son[i]][k]来,当换另一个son2[i],dp[i][j]就是由俩个son推出,其他son同理;

                  4:对于一棵树,可以随意选一个点为根,开一个vis[]数组,记录该结点是否访问过;

                        

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

                  最裸的树形DP, 定义dp[i][0]表示以i为根的子树不选i能邀请到的最大值;

                  Dp[i][1]表示以i为根的子树选i能邀请到的最大值;

                  状态转移:dp[i][0]+=max(dp[son][0],dp[son][1]);   dp[i][1]+=dp[son][0];

                  注意每个点的值有正有负;

        

    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #include<cstdlib>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 const int MAXN=6010;
    10 int dp[MAXN][2];
    11 const int INF=1000000; 
    12 vector <int > g[MAXN];
    13 int c[MAXN];
    14 int n;
    15 int v[MAXN]; 
    16 void TREEDP(int root)
    17 {
    18         int d=g[root].size();
    19         if (d==0) {
    20                    dp[root][1]=c[root];
    21                    dp[root][0]=0;
    22                   return ;                 
    23          } 
    24         for (int i=0;i<d;i++)
    25         {
    26             int c=g[root][i]; 
    27              TREEDP(c); 
    28         } 
    29          
    30         dp[root][1]=c[root];
    31         for (int i=0;i<d;i++)
    32         {
    33              int c=g[root][i];
    34              if (dp[c][0]>0) 
    35               dp[root][1]+=dp[c][0]; 
    36         } 
    37         dp[root][0]=-INF;
    38         for (int i=0;i<d;i++)
    39         {
    40               int c=g[root][i];
    41               int t=max(dp[c][1],dp[c][0]); 
    42               if (t>0  && dp[root][0]<0)
    43              {
    44                    dp[root][0]=t;
    45                 }      else if (t<0 && dp[root][0]<0)
    46              {
    47                    if (dp[root][0]<t) dp[root][0]=t;   
    48              }     else if (t>0  && dp[root][0]>=0)
    49              {
    50                    dp[root][0]+=t; 
    51              }  
    52         } 
    53 } 
    54 int main()
    55 {
    56    // freopen("D:\in.txt","r",stdin);    
    57     while (~scanf("%d",&n))
    58     {
    59            for (int i=1;i<=n;i++)
    60          {
    61              scanf("%d",&c[i]); 
    62              g[i].clear(); 
    63          } 
    64          int u,v;
    65          bool  vis[MAXN];
    66          memset(vis,0,sizeof(vis)); 
    67          while (~scanf("%d%d",&u,&v)) 
    68            {
    69                  if (u==0 && v==0) break; 
    70                 g[v].push_back(u);  
    71                   vis[u]=1; 
    72          } 
    73          memset(dp,0,sizeof(dp)); 
    74          
    75          for (int i=1;i<=n;i++)
    76          {
    77                   if (vis[i]==0)
    78                 {
    79                     TREEDP(i);
    80                     cout<<max(dp[i][0],dp[i][1])<<endl; 
    81                     break; 
    82                 } 
    83          } 
    84          
    85          
    86     } 
    87 
    88     return 0;
    89 }

                 

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

                  和上一题基本一样,但还要询问方案是否唯一;加一个数组记录当前状态是否唯一如果不唯一,当根结点的状态有它推出时,根结点的状态也就不唯一

                    //程序统一输出的方式,不要cout和printf混用,俩着输出性质不一样;

              

    View Code
      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<map>
      7 #include<vector> 
      8 #include<string> 
      9 using namespace std;
     10 const int MAXN=210;
     11 map<string,int > mp;
     12 int sz; 
     13 vector <int >g[MAXN]; 
     14 int dp[MAXN][2];
     15 int dug[MAXN][2]; 
     16 int vis[MAXN];
     17 int n; 
     18 void init()
     19 {
     20      sz=0;
     21     mp.clear();
     22     for (int i=0;i<n;i++) g[i].clear(); 
     23      memset(vis,0,sizeof(vis)); 
     24 } 
     25 void TREEDP(int rt)
     26 {
     27           if (vis[rt]) return ;
     28         vis[rt]=1; 
     29         int d=g[rt].size();
     30         if (d==0)
     31         {
     32                 dp[rt][0]=0;
     33                 dp[rt][1]=1;
     34                 dug[rt][0]=1;
     35                 dug[rt][1]=1; 
     36                 return; 
     37         }
     38         dp[rt][0]=dp[rt][1]=0; 
     39         dug[rt][0]=dug[rt][1]=1; 
     40         for (int i=0;i<d;i++)
     41         {
     42                 int c=g[rt][i];
     43                 if (!vis[c])
     44                 {
     45                        TREEDP(c);
     46                 }        
     47                 dp[rt][1]+=dp[c][0];
     48                 if (dug[c][0]==0) dug[rt][1]=0;  
     49                 dp[rt][0]+=max(dp[c][1],dp[c][0]);
     50                 if (dp[c][1]>dp[c][0] && dug[c][1]==0)
     51                 {
     52                         dug[rt][0]=0; 
     53                 } else
     54                 if (dp[c][1]<dp[c][0] && dug[c][0]==0)
     55                 {
     56                         dug[rt][0]=0; 
     57                 } else if (dp[c][1]==dp[c][0]) dug[rt][0]=0; 
     58         } 
     59         dp[rt][1]+=1; 
     60          
     61 
     62 } 
     63 int mp_find(string s)
     64 {
     65     if (mp.find(s)==mp.end()) 
     66     {
     67             mp[s]=sz++; 
     68     } 
     69     return mp[s]; 
     70 } 
     71 int main()
     72 {
     73     //freopen("D:\in.txt","r",stdin); 
     74     string s,s1,s2; 
     75     while (cin>>n)
     76     {
     77             if (n==0) break;
     78             init(); 
     79             cin>>s; 
     80              mp_find(s); 
     81              for (int i=0;i<n-1;i++)
     82             {
     83                  cin>>s1>>s2;
     84                 int u=mp_find(s1);
     85                 int v=mp_find(s2);
     86                 g[v].push_back(u); 
     87             } 
     88             
     89             TREEDP(0);
     90             
     91             if (dp[0][1]>dp[0][0])
     92             {
     93                  if(dug[0][1]) cout<<dp[0][1]<<" Yes"<<endl;//printf("%d Yes\n",dp[0][1]);
     94                 else cout<<dp[0][1]<<" No"<<endl;//printf("%d No\n",dp[0][1]); 
     95             } else if (dp[0][1]<dp[0][0]) 
     96             {
     97                  if(dug[0][0])cout<<dp[0][0]<<" Yes"<<endl;// printf("%d Yes\n",dp[0][0]);
     98                 else cout<<dp[0][0]<<" No"<<endl;//printf("%d No\n",dp[0][0]); 
     99             } else 
    100             {
    101                 cout<<dp[0][1]<<" No"<<endl;//printf("%d No\n",dp[0][1]); 
    102             
    103             } 
    104             
    105     
    106     }        
    107 
    108 
    109     return 0; 
    110 } 

       

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

                  很裸的树形DP,先一遍dfs,统计出以每个结点为根的子树包含的队伍,和该子树以该子树跟为聚集地所走的路径,这样就算出了以根结点为聚集地需要的总路程;

                  再一遍   dfs,由总根结点推到子结点,记录下最小值。

                  //对于数据大的,但有感觉没有超,还是果断用long long ,有可能中间计算超了;

                  //该题用dfs递归会爆栈,要手写stack,或用C++交可以用爆栈外挂,

                   #pragma comment(linker, "/STACK:1024000000,1024000000")

    View Code
      1 #pragma comment(linker, "/STACK:1024000000,1024000000")
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<cstdlib>
      7 #include<cmath>
      8 #include<vector>
      9 using namespace std;
     10 const int N=100100;
     11 typedef __int64 ll;
     12 ll dp[N];
     13 ll dug[N];
     14 int n;
     15 ll c[N],vis[N];
     16 ll ans;
     17 struct node
     18 {
     19         int v,w;
     20 };
     21 vector <node> g[N];
     22 void TREEDP(int rt)
     23 {
     24         vis[rt]=1;
     25         int d=g[rt].size();
     26         if (d==0)
     27         {
     28                 dp[rt]=c[rt];
     29                 dug[rt]=0;
     30                 return;
     31         }
     32         dp[rt]=c[rt];
     33         dug[rt]=0;
     34         for (int i=0;i<d;i++)
     35         {
     36                 int c=g[rt][i].v;
     37                 int w=g[rt][i].w;
     38                 if (vis[c]) continue;
     39                 TREEDP(c);
     40                 dp[rt]+=dp[c];
     41                 dug[rt]+=dp[c]*w+dug[c];    
     42         }
     43 }
     44 void init()
     45 {
     46         memset(dp,0,sizeof(dp));
     47         for (int i=1;i<=n;i++) g[i].clear();
     48           memset(vis,0,sizeof(vis));
     49           memset(dug,0,sizeof(dug));
     50 }
     51 void solve(int rt)
     52 {
     53         vis[rt]=1;
     54         int d=g[rt].size();
     55         for (int i=0;i<d;i++)
     56         {
     57                 int c=g[rt][i].v;
     58                 if (vis[c]) continue;
     59                 int w=g[rt][i].w;
     60                 ll t1=dp[c],t2=dug[c];
     61                 ll t3=dp[rt],t4=dug[rt];
     62                 
     63                 dp[c]=t3;
     64                 dp[rt]=t3-t1;
     65                 dug[rt]=t4-t1*w-t2;
     66                 dug[c]=t4-w*t1+(t3-t1)*w;
     67                 ans=min(dug[c],ans);    
     68                 solve(c);
     69                 dp[c]=t1;dug[c]=t2;
     70                 dp[rt]=t3;dug[rt]=t4;            
     71         }
     72           vis[rt]=0;
     73 
     74 }
     75 int main()
     76 {    
     77         //freopen("D:\in.txt","r",stdin);
     78         while (~scanf("%d",&n))
     79         {
     80                 for (int i=1;i<=n;i++)
     81                 {
     82                         scanf("%I64d",&c[i]); 
     83                 }
     84                 init(); 
     85                 for (int i=0;i<n-1;i++)
     86                 {
     87                         int u,v,w;
     88                         scanf("%d%d%d",&u,&v,&w);
     89                         node t1={v,w};
     90                         g[u].push_back(t1);
     91                           node t2={u,w};
     92                           g[v].push_back(t2);
     93                 }
     94                 TREEDP(1);
     95                 ans=dug[1];
     96                 //cout<<ans<<endl;
     97                 memset(vis,0,sizeof(vis));
     98                 solve(1); 
     99                 printf("%I64d\n",ans);
    100         
    101         } 
    102 
    103         return 0;
    104 }

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

                  求树上离一个点最远的距离;我是先一遍dfs记录下以该点为根的子树的子结点到根的最远距离,然后转移总根结点,求出每个结点的ans;同上类似;

                   

    View Code
      1     
      2 #include<cstdio>
      3 #include<iostream>
      4 #include<cstring>
      5 #include<algorithm>
      6 #include<cstdlib>
      7 #include<cmath>
      8 #include<vector>
      9 using namespace std;
     10 typedef long long ll;
     11 const int N=10010;
     12 ll dp[N];
     13 struct node
     14 {
     15         int v,w;
     16 };
     17 vector<node> g[N];
     18 int vis[N];
     19 ll c[N];
     20 int n;
     21 void init()
     22 {
     23         for (int i=1;i<=n;i++)
     24         g[i].clear();
     25         memset(dp,0,sizeof(dp));
     26         memset(vis,0,sizeof(vis));
     27 }
     28 void TREEDP(int rt)
     29 {
     30         vis[rt]=1;
     31         int d=g[rt].size();
     32         if (d==0)
     33         {
     34                 dp[rt]=0;
     35                 return;
     36         }
     37         for (int i=0;i<d;i++)
     38         {
     39                 ll v=g[rt][i].v;
     40                 ll w=g[rt][i].w;
     41                 if (vis[v]) continue;
     42                 TREEDP(v);
     43                 dp[rt]=max(dp[rt],dp[v]+w);
     44         } 
     45 
     46 }
     47 ll find(int rt,int x)
     48 {
     49         ll t=0;
     50         int d=g[rt].size();
     51         for (int i=0;i<d;i++)
     52         {
     53                 int v=g[rt][i].v;
     54                 int w=g[rt][i].w;
     55                 if(x==v) continue;
     56                 t=max(t,dp[v]+w);
     57         }
     58           return t;
     59 }
     60 void solve(int rt)
     61 {
     62         vis[rt]=1;
     63         int d=g[rt].size();
     64         if (d==0)
     65         {
     66                 c[rt]=dp[rt];
     67                 return;
     68         }        
     69         for (int i=0;i<d;i++)
     70         {
     71                 int v=g[rt][i].v;
     72                 if (vis[v]) continue;
     73                 ll w=g[rt][i].w;
     74                 ll t=dp[v],t3=dp[rt];
     75                 ll t2=find(rt,v)+w;
     76         
     77                  
     78                 dp[v]=max(dp[v],t2);
     79                 dp[rt]=t2-w;
     80                 c[v]=dp[v];
     81                 solve(v);
     82                 dp[rt]=t3;dp[v]=t;
     83                 
     84         }
     85 
     86 }
     87 int main()
     88 {
     89         //freopen("D:\in.txt","r",stdin);
     90         while (~scanf("%d",&n))
     91         {
     92                  init();
     93                 for (int i=2;i<=n;i++)
     94                 {
     95                         int v,w;
     96                         scanf("%d%d",&v,&w);
     97                         node t1={v,w};
     98                         g[i].push_back(t1);
     99                         node t2={i,w};
    100                         g[v].push_back(t2);
    101                 }
    102 
    103                 TREEDP(1);
    104                 c[1]=dp[1];
    105                 memset(vis,0,sizeof(vis));
    106                 solve(1);    
    107                 for (int i=1;i<=n;i++)
    108                 printf("%d\n",c[i]);    
    109         
    110         }
    111         return 0;
    112 }

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

                    二分+树形DP;

                    据说凡是求最大最小值或最小最大值都可以二分确定一个因素,然后验证;

                    二分上限,树形DP求不超上界切断联络的最小代价;

    View Code
      1 #include<cstdio>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<cmath>
      7 #include<vector>
      8 using namespace std;
      9 const int N=1010;
     10 int dp[N];
     11 int n,all;
     12 int vis[N];
     13 bool bo[N];
     14 struct node
     15 {
     16         int v,w;
     17 };
     18 vector<node> g[N];
     19 
     20 const int INF=1000000000;
     21 void TREEDP(int rt,int c,int m)
     22 {
     23         vis[rt]=1;
     24         int d=g[rt].size();
     25     
     26         int t=0;
     27         int flag=0;
     28         for (int i=0;i<d;i++)
     29         {
     30                 int v=g[rt][i].v;
     31                 int w=g[rt][i].w;
     32                 if (vis[v]) continue;
     33                 TREEDP(v,w,m);
     34                 if (bo[v]) 
     35                 {
     36                         bo[rt]=1;
     37                         break;
     38                 }
     39                 t+=dp[v];
     40                 flag=1;
     41         }
     42         if (bo[rt]==1)
     43         {
     44                 if (c<=m)
     45                 {
     46                         bo[rt]=0;
     47                         dp[rt]=c;
     48                 }
     49         } else 
     50         {
     51                 if (c<=m)
     52                 {
     53                         if (flag)
     54                         dp[rt]=min(t,c);
     55                         else dp[rt]=c;
     56                 }else     
     57                 {        
     58                         if (flag)
     59                         dp[rt]=t;
     60                         else bo[rt]=1;
     61                         
     62                 }
     63         }
     64         
     65 }
     66 bool solve(int m)
     67 {
     68         memset(dp,0,sizeof(dp));
     69         memset(vis,0,sizeof(vis));
     70         memset(bo,0,sizeof(bo));
     71         TREEDP(1,INF,m);
     72         if (bo[1]==1)  return 0;
     73         if(dp[1]<=all) return 1;
     74         return 0;        
     75 }
     76 void init()
     77 {
     78         for (int i=1;i<=n;i++)
     79         g[i].clear();
     80 }
     81 int main()
     82 {
     83         //freopen("D:\in.txt","r",stdin);
     84         while (~scanf("%d%d",&n,&all))
     85         {
     86                 if (n==0 && all==0) break;
     87                 init();
     88                 int l=0,r=1000;
     89                 for (int i=2;i<=n;i++)
     90                 {
     91                         int u,v,w;
     92                         scanf("%d%d%d",&u,&v,&w);
     93                     //    r=max(r,w);
     94                         
     95                         node t1={v,w};
     96                         g[u].push_back(t1);
     97                         node t2={u,w};
     98                         g[v].push_back(t2);
     99                 }
    100                 int ans=-1;
    101                 while (r>l)
    102                 {
    103                         int m=(l+r)/2;
    104                         if (solve(m))
    105                         {
    106                                 ans=m;
    107                                 r=m;
    108                         }else     l=m+1;
    109                 }
    110                 printf("%d\n",ans);
    111                 
    112                 
    113         }
    114         return 0;
    115 }

       

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

                         dp[i][j]表示以i为根,攻下j个城市的最大获得;

                         dp[i][j]=max(dp[i][j[,dp[son][k]+dp[i][j-k]);类似于在树上做分组背包;

                        

                        

    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cstdlib>
     6 #include<cmath>
     7 #include<vector> 
     8 using namespace std;
     9 const int MAXN=210;
    10 int n,m;
    11 vector<int > g[MAXN];
    12 int dp[MAXN][MAXN]; 
    13 //dp[i][j] ,表示以i为根,攻下j个城市的最大获得; 
    14 int c[MAXN]; 
    15 void init()
    16 {
    17                    memset(dp,0,sizeof(dp));
    18                 for (int i=0;i<=n;i++)
    19                 {
    20                         g[i].clear(); 
    21                 } 
    22 
    23 } 
    24 void TREEDP(int rt,int m)
    25 {
    26         
    27         int d=g[rt].size();    
    28         dp[rt][1]=c[rt];    
    29         for (int i=0;i<d;i++)
    30         {
    31                   
    32                 int c=g[rt][i];
    33                 if (m>1) 
    34                 TREEDP(c,m-1);
    35                 for (int j=m;j>0;j--)
    36                 {
    37                          int v=j+1;
    38                         for (int k=1;k<v;k++) 
    39                         if (dp[rt][v]<dp[rt][v-k]+dp[c][k])
    40                         {
    41                                 dp[rt][v]=dp[rt][v-k]+dp[c][k]; 
    42                         } 
    43                 
    44                 } 
    45         } 
    46 
    47 } 
    48 int main()
    49 {
    50     //    freopen("D:\in.txt","r",stdin); 
    51         while (~scanf("%d%d",&n,&m)) 
    52         {
    53                 if (n==0 && m==0) break; 
    54                 c[0]=0; init(); 
    55                 for (int i=1;i<=n;i++)
    56                 {
    57                         int v; 
    58                         scanf("%d%d",&v,&c[i]);
    59                         g[v].push_back(i); 
    60                 }
    61                 TREEDP(0,m+1);        
    62                 printf("%d\n",dp[0][m+1]); 
    63         
    64         }
    65         return 0; 
    66 } 

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

                         同上;注意特判;

    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<iostream>
     6 #include<cmath>
     7 #include<vector>
     8 using namespace std;
     9 
    10 const int MAXN=110;
    11 int n,m;
    12 vector<int > g[MAXN];
    13 int c[MAXN],w[MAXN];
    14 int dp[MAXN][MAXN];
    15 int vis[MAXN]; 
    16 //dp[i][j] 以i为根花费j能获得的最大利益; 
    17 
    18 void TREEDP(int rt)
    19 {
    20     
    21         vis[rt]=1;
    22         int d=g[rt].size(); 
    23         for (int i=c[rt];i<=m;i++) dp[rt][i]=w[rt]; 
    24         for (int i=0;i<d;i++)
    25         {
    26                 int son=g[rt][i]; 
    27                 if (vis[son]==0)
    28                 { 
    29                         TREEDP(son);
    30                 
    31                         for (int j=m;j>=c[rt];j--)
    32                         {
    33                             
    34                                 for (int k=1;j+k<=m;k++)
    35                                 {
    36                                         if (dp[son][k])
    37                                         dp[rt][j+k]=max(dp[rt][j+k],dp[rt][j]+dp[son][k]); 
    38                         
    39                                 } 
    40                         } 
    41                 } 
    42         
    43         } 
    44 } 
    45 void init()
    46 {
    47         memset(dp,0,sizeof(dp));
    48         for (int i=0;i<=n;i++) g[i].clear();
    49         memset(vis,0,sizeof(vis)); 
    50 } 
    51 int main()
    52 {
    53         //freopen("D:\in.txt","r",stdin); 
    54         while (~scanf("%d%d",&n,&m)) 
    55          {
    56                  if (n==-1 && m==-1) break; 
    57                 init(); 
    58                 for (int i=1;i<=n;i++)
    59                 {
    60                         int a,b;
    61                         scanf("%d%d",&a,&b);
    62                         c[i]=(a+19)/20;
    63                     //    if (a%20) c[i]+=1;
    64                         w[i]=b; 
    65                 } 
    66                 for (int i=0;i<n-1;i++)
    67                 {
    68                         int u,v;
    69                         scanf("%d%d",&u,&v);
    70                         g[u].push_back(v);
    71                         g[v].push_back(u); 
    72                 } 
    73                 if (m==0)
    74                 {
    75                         printf("0\n");
    76                         continue; 
    77                 } 
    78                 TREEDP(1);
    79                 printf("%d\n",dp[1][m]); 
    80         
    81         } 
    82         return 0; 
    83 } 

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

                         题意差不多,但要特别处理0的情况;          

    View Code
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<iostream>
     6 #include<vector>
     7 #include<cmath>
     8 using namespace std;
     9 const int N=10010;
    10 int dp[N][11];
    11 int n,s,num;
    12 int vis[N];
    13 struct node
    14 {
    15         int v,w;
    16 };
    17 vector<node > g[N];
    18 const int INF=1000000000;
    19 
    20 
    21 void TREEDP(int rt)
    22 {
    23         vis[rt]=1;
    24         int d=g[rt].size();
    25         for (int i=0;i<d;i++)
    26         {
    27                 int v=g[rt][i].v;
    28                 int w=g[rt][i].w;
    29                 if (vis[v]) continue;
    30                 TREEDP(v);
    31                 for (int j=num;j>=0;j--)
    32                 {
    33                         int t=INF;
    34                         for (int k=0;k<=j;k++)
    35                         {
    36                             
    37                                 if (j-k==0)
    38                                  t=min(t,dp[rt][k]+dp[v][j-k]+w*2);
    39                                  else t=min(t,dp[rt][k]+dp[v][j-k]+w*(j-k));
    40                                  
    41                         }
    42                         dp[rt][j]=t;
    43                 }
    44         }
    45         
    46 }
    47 void init()
    48 {
    49         memset(dp,0,sizeof(dp));
    50         memset(vis,0,sizeof(vis));
    51         for (int i=0;i<=n;i++) g[i].clear();
    52 
    53 }
    54 int main()
    55 {
    56         //freopen("D:\in.txt","r",stdin);
    57         while (~scanf("%d%d%d",&n,&s,&num))
    58         {
    59                 init();
    60                 for (int i=0;i<n-1;i++)
    61                 {
    62                         int u,v,w;
    63                         scanf("%d%d%d",&u,&v,&w);
    64                         node t1={v,w};
    65                         g[u].push_back(t1);
    66                         node t2={u,w};
    67                         g[v].push_back(t2);
    68 
    69                 }
    70             //    init_dp(s);
    71                 memset(vis,0,sizeof(vis));
    72                 TREEDP(s);
    73                 printf("%d\n",dp[s][num]);
    74         }
    75         return 0;
    76 }

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

                         这题主要还是缩点;树形DP,就随便搞一下;

                        

    View Code
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstdlib>
    #include<algorithm>
    #include<stack> 
    using namespace std;
    const int M=20005;
    const int N=10005;
    const int INF=1000000000; 
    struct node
    {
        int u,v;
        int next; 
    }edge[M*2],edge1[M*2];
    int head[N],tol,cnt,dfn[N],low[N],vis[N],belong[N];
    int toll,head1[N],val[N],val1[N]; 
    int n,m,SUM,Min,scc;
    stack<int > S; 
    void insert(int a,int b)
    {
            node v={a,b,head[a]};
            edge[tol]=v;
            head[a]=tol++; 
    } 
    void insert1(int a,int b)
    {
            node v={a,b,head1[a]};
            edge1[toll]=v;
            head1[a]=toll++; 
    } 
    void tarjan(int u,int father)
    {
            int j,v,flag;
            dfn[u]=low[u]=cnt++; 
            vis[u]=1;
            S.push(u); 
            flag=0;
            for (j=head[u];j!=-1;j=edge[j].next) 
            {
                    v=edge[j].v; 
                      if (v==father && !flag)
                    {
                           flag=1;continue; 
                    } 
                    if (!vis[v]) tarjan(v,u);
                    low[u]=min(low[u],low[v]); 
            } 
            if (dfn[u]==low[u])
            {
                    scc++;
                    do
                    {
                        v=S.top();S.pop(); 
                        belong[v]=scc;
                        val[scc]+=val1[v]; 
                    } while (v!=u) ; 
            } 
    } 
    int dfs(int u,int father)
    {
            int j,v,sum;
            sum=val[u];
            for (j=head1[u];j!=-1;j=edge1[j].next) 
              {
                    v=edge1[j].v; 
                      if (v==father) continue;
                    sum+=dfs(v,u); 
            } 
            Min=min(Min,abs(SUM-2*sum)) ; 
            return sum; 
    } 
    int main()
    {
         while (~scanf("%d%d",&n,&m))
        {
                memset(head,-1,sizeof(head));
                tol=cnt=0;
                SUM=0;
                for (int i=0;i<n;i++)
                {
                        scanf("%d",&val1[i]);
                        SUM+=val1[i]; 
                } 
                for (int i=0;i<m;i++)
                {
                         int u,v; 
                        scanf("%d%d",&u,&v); 
                        insert(u,v);
                        insert(v,u); 
                } 
                memset(vis,0,sizeof(vis));
                memset(val,0,sizeof(val)); 
                  scc=0;
                  while (!S.empty())S.pop(); 
                tarjan(0,0); 
                if (scc==1)
                {
                        printf("impossible\n");
                        continue; 
                } 
                toll=0;
                memset(head1,-1,sizeof(head1));
                for (int i=0;i<tol;i++)
                {
                        int a=edge[i].u;
                        int b=edge[i].v; 
                          if (belong[a]!=belong[b])
                        insert1(belong[a],belong [b]); 
                } 
                Min=INF; 
                dfs(1,0);
                printf("%d\n",Min); 
        } 
    
         return 0; 
    } 

                 

                        

                        

                                                                         

                

                        

                                                                         

                

  • 相关阅读:
    jQuery实现每隔几条元素增加1条线的方法
    Unity3D for Mac 破解
    IOS
    Unity3D 动态地创建识别图
    Easy AR简单教程
    iOS对象(数组)转化为JSon字符串
    iOS对象(字典或数组)转化为JSon字符串
    iOS
    iOS 逆向
    ios-逆向 手把手安装最新版Theos
  • 原文地址:https://www.cnblogs.com/Rlemon/p/2622493.html
Copyright © 2011-2022 走看看