hdu - 4340 - Capturing a country - 樹形dp

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

題意:

題意:兩個人進攻n個城市的國家,這n個城市構成一棵樹,可以任意選擇一個點開始,攻擊已被自己攻擊過的點的相鄰點,時間可以減半,兩個人的攻擊時間不一
這個狀態要求這個連通塊有一個入口嘛


顯然題中給圖的是一顆樹。問題可以抽象成對樹的每個點都染色,有兩中顏色可以選擇。
我們可以知道,如果某一個連通的點集染的是同一種顏色,則這個集合中只要而且必須有一個點取完整的費用,其他的點都只需要對應費用的一半。
狀態:dp[i][j][k] (0 <= i <= n, 0<=j<=1, 0 <= k <= 1) 表示以i爲根的子樹的費用,其中i節點被染成了第j種顏色,且子樹中與i染成同一種顏色的與i連通的點集有k個點選取了完整的費用。
若選取1爲根節點,則最後需要的結果爲: min(dp[1][0][1], dp[1][1][1]}。
狀態轉移方程:
v爲i節點的兒子節點。令 S = sum{min(dp[v][j][0], dp[v][1-j][1])}, det = min{dp[v][j][1] - min(dp[v][j][0], dp[v][1-j][1])};
dp[i][j][0] = cost[i][j]/2 + S;
dp[i][j][1] = min(cost[i][j] + S, cost[i][j]/2 + S + det);

#include<cstdio>
 #include<cstring>
 #include<iostream>
 #include<algorithm>
 #include<set>
 #include<map>
 #include<queue>
 #include<vector>
 #include<string>
 #define Min(a,b) a<b?a:b
 #define Max(a,b) a>b?a:b
 #define CL(a,num) memset(a,num,sizeof(a));
 #define maxn  205
 #define inf 9999999
 #define mx 1<<60
 using namespace std;
 vector<__int64>g[maxn];
 int dp[maxn][2][2],a[2][maxn],vis[maxn];
 void dfs(int k)
 {
     int i,j;
     int  len = g[k].size();
     if( len == 0)//  爲葉子節點
     {
         dp[k][0][0] = a[0][k]/2;
         dp[k][0][1] = a[0][k];
         dp[k][1][0] = a[1][k]/2;
         dp[k][1][1] = a[1][k];
         return ;
     }

     for( i = 0;i < 2; ++i)
     {
         int sum = 0,det = inf ,tmp;
         for( j = 0; j < len ;++j)
         {
             dfs(g[k][j]);
             int w = g[k][j];
             tmp = min(dp[w][i][0],dp[w][1 - i][1]);
             sum +=tmp;
             det = min(det,dp[w][i][1] - tmp);
         }
         dp[k][i][0]  = sum + a[i][k]/2;
         dp[k][i][1]  = min(a[i][k] + sum ,a[i][k]/2 + sum + det);
     }
 }
 int main()
 {
     int n, i, j,x,y,root;
     while(scanf("%d",&n)!=EOF)
     {
         for(j = 0; j < 2 ;++j)
         {
             for( i = 1; i <= n ;++i )
             scanf("%d",&a[j][i]);
         }
         CL(vis,0);
         for(i = 0;i <= n;i++)g[i].clear();
         for(i = 0; i < n - 1 ;++i)
         {
           scanf("%d%d",&x,&y);
           if( i ==0) root = x;//建的圖是有向圖,對解決問題沒有影響,樹形dp 就是 這樣
           if(!vis[y])
           {
               g[x].push_back(y);
               vis[x] = 1;
           }
           else g[y].push_back(x);

         }
         CL(dp,0);
         dfs(root);
         int t1 = dp[root][0][1];
         int t2 = dp[root][1][1];
         printf("%d\n",min(t1,t2));
     }
 }


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章