Uva-12093 Protecting Zonk(较复杂的树形DP)

来源:互联网 发布:ssd优化工具 编辑:程序博客网 时间:2024/06/15 09:14

题意:给定一个有n(n <= 10000) 个节点的无根树.有两种装置A和B,每种都有无线多个.

在某个节点x使用A装置需要C1(C1 <= 1000)的花费,并且此时与节点x相连的边都被覆盖.

在某个节点X使用B装置需要C2(C2 <= 1000)的费用,并且此时与节点x相连的边以及与节点x相连的点相连的边都被覆盖.

求覆盖所有边的最小花费.


分析:状态有很多种表示方法,f[u][a][b][c] 表示第i个点选了a装置,他父亲选了b装置,c表示它的儿子中是否有选C2装置,或者f[u][a][b][c]表示第i个点选了a装置,他父亲选了b装置,c表示u到fa[u]的边是否被u上边的点覆盖,这两种状态定义方法都能转移,其实这道题的状态表示方法不难想到,难就在这个状态猛一看很多,给人一种无从下手的感觉,其实手动列一下这18个状态就会发现它们的转移其实一共就三种类型.



第二种状态表示方法:

#include <bits/stdc++.h>#define N 10005#define INF 1047483647#define MOD 1000000007using namespace std;int n,u,v,c1,c2,f[N][3][3][2],dp[N][2];vector<int> G[N];void dfs(int u,int fa){for(int v : G[u]) if(v != fa) dfs(v,u);for(int i = 0;i < 3;i++) for(int j = 0;j < 3;j++)  for(int k = 0;k < 2;k++)  {      if(!k && j) continue;      f[u][i][j][k] = !i ? 0:(i == 1 ? c1 : c2);      int t = 0,V_tot = 0;    dp[0][1] = INF;   for(int v : G[u])  if(v != fa)  {   t++;   V_tot += min(min(f[v][0][i][i || (j==2)],f[v][1][i][i || (j==2)]),f[v][2][i][i || (j==2)]);  dp[t][0] = dp[t-1][0] + min(f[v][0][i][1],f[v][1][i][1]);   dp[t][1] = min(dp[t-1][1] + min(f[v][2][i][1],min(f[v][0][i][1],f[v][1][i][1])),dp[t-1][0] + f[v][2][i][0]);  }  if(!(i+j+k)) f[u][i][j][k] += dp[t][1];  else    if(!i && j < 2) f[u][i][j][k] += min(dp[t][1],V_tot);   else f[u][i][j][k] += V_tot;   }}int main(){while(~scanf("%d%d%d",&n,&c1,&c2) && (n+c1+c2)){for(int i = 1;i <= n;i++) G[i].clear();for(int i = 1;i < n;i++){scanf("%d%d",&u,&v);G[u].push_back(v);G[v].push_back(u);}dfs(1,0);cout<<min(min(f[1][0][0][1],f[1][1][0][1]),f[1][2][0][1])<<endl;}}

第一种状态表示方法:


#include <bits/stdc++.h>#define N 10005#define INF 1047483647#define MOD 1000000007using namespace std;int n,u,v,c1,c2,f[N][3][3][2],dp[N][2];vector<int> G[N];void dfs(int u,int fa){for(int v : G[u]) if(v != fa) dfs(v,u);for(int i = 0;i < 3;i++) for(int j = 0;j < 3;j++)  for(int k = 0;k < 2;k++)  {    f[u][i][j][k] = !i ? 0:(i == 1 ? c1 : c2);      int t = 0;    dp[0][1] = INF;   for(int v : G[u])  if(v != fa)  {   t++;   dp[t][0] = dp[t-1][0] + min(min(f[v][0][i][1],f[v][0][i][0]),min(f[v][1][i][1],f[v][1][i][0]));    dp[t][1] = min(dp[t-1][1] + min(min(f[v][2][i][1],f[v][2][i][0]),min(min(f[v][0][i][1],f[v][0][i][0]),min(f[v][1][i][1],f[v][1][i][0]))),dp[t-1][0] + min(f[v][2][i][1],f[v][2][i][0]));  }  if(k == 1) f[u][i][j][k] += dp[t][1];  else   if(!(i+k) && j < 2)  {   for(int v : G[u])       if(v != fa)       f[u][i][j][k] += min(min(f[v][1][i][0],f[v][1][i][1]),f[v][0][i][1]);  }  else f[u][i][j][k] += dp[t][0];  }}int main(){while(~scanf("%d%d%d",&n,&c1,&c2) && (n+c1+c2)){for(int i = 1;i <= n;i++) G[i].clear();for(int i = 1;i < n;i++){scanf("%d%d",&u,&v);G[u].push_back(v);G[v].push_back(u);}dfs(1,0);cout<<min(min(min(f[1][0][0][1],f[1][0][0][0]),min(f[1][1][0][1],f[1][1][0][0])),min(f[1][2][0][1],f[1][2][0][0]))<<endl;}}



0 0