POJ3345 Bribing FIPA(树形DP)

题意:有n个国家,贿赂它们都需要一定的代价,一个国家被贿赂了从属这个国家的国家也相当于被贿赂了,问贿赂至少k个国家的最少代价。

这些国家的从属关系形成一个森林,加个超级根连接,就是一棵树了,考虑用DP:

  • dp[u][m]表示以u国家为根的子树贿赂m个国家的最少代价

单单这样的话转移是指数级的,其实这题就是树上背包,同HDU1516。现在觉得想明白了,其实就是所有结点为根做n次01背包,每次01背包的物品就是当前根的各个儿子。

状态加一维度表示,转移就可以不是指数级了:

  • dp[u][n][m]表示以u国家为根的前n个儿子构成的子树贿赂m个国家的最少代价

然后其实循环利用内存,像01背包一样省去一维背包从大到小枚举,然后就是那样了。。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<string>
  5 #include<algorithm>
  6 using namespace std;
  7 #define INF (1<<29)
  8 #define MAXN 222
  9 
 10 struct Edge{
 11     int u,v,next;
 12 }edge[MAXN];
 13 int NE,head[MAXN];
 14 void addEdge(int u,int v){
 15     edge[NE].u=u; edge[NE].v=v; edge[NE].next=head[u];
 16     head[u]=NE++;
 17 }
 18 
 19 int n,k,cost[MAXN],d[MAXN][MAXN],size[MAXN];
 20 void getsize(int u){
 21     size[u]=1;
 22     for(int i=head[u]; i!=-1; i=edge[i].next){
 23         int v=edge[i].v;
 24         getsize(v);
 25         size[u]+=size[v];
 26     }
 27 }
 28 void dfs(int u){
 29     if(u) d[u][size[u]]=cost[u];
 30     for(int i=head[u]; i!=-1; i=edge[i].next){
 31         int v=edge[i].v;
 32         dfs(v);
 33         for(int j=size[u]; j>=0; --j){
 34             for(int k=0; k<j; ++k) d[u][j]=min(d[u][j],d[u][k]+d[v][j-k]);
 35         }
 36     }
 37 }
 38 
 39 bool read(char *&s,int &t){
 40     if(sscanf(s,"%d",&t)!=1) return 0;
 41     while(*s==' ') ++s;
 42     while(*s>='0' && *s<='9') ++s;
 43     while(*s==' ') ++s;
 44     return 1;
 45 }
 46 bool read(char *&s,char *str){
 47     if(sscanf(s,"%s",str)!=1) return 0;
 48     while(*s==' ') ++s;
 49     while(*s && *s!=' ') ++s;
 50     while(*s==' ') ++s;
 51     return 1;
 52 }
 53 
 54 char str[11111];
 55 string name[MAXN<<3];
 56 int main(){
 57     int w[MAXN]; char ts[MAXN];
 58     while(gets(str) && str[0]!='#'){
 59         char *s=str;
 60         read(s,n); read(s,k);
 61 
 62         int nn=1;
 63         vector<string> vec[MAXN];
 64         for(int i=0; i<n; ++i){
 65             gets(str); s=str;
 66             read(s,ts); name[nn++]=ts; vec[i].push_back(ts);
 67             read(s,w[i]);
 68             while(read(s,ts)){
 69                 name[nn++]=ts; vec[i].push_back(ts);
 70             }
 71         }
 72         sort(name+1,name+nn);
 73         nn=unique(name+1,name+nn)-name;
 74 
 75         NE=0;
 76         memset(head,-1,sizeof(head));
 77         int deg[MAXN]={0};
 78         for(int i=0; i<n; ++i){
 79             int u=lower_bound(name+1,name+nn,vec[i][0])-name;
 80             cost[u]=w[i];
 81             for(int j=1; j<vec[i].size(); ++j){
 82                 int v=lower_bound(name+1,name+nn,vec[i][j])-name;
 83                 addEdge(u,v); ++deg[v];
 84             }
 85         }
 86         for(int i=1; i<=n; ++i){
 87             if(deg[i]==0) addEdge(0,i);
 88         }
 89 
 90         getsize(0);
 91         for(int i=0; i<=n; ++i){
 92             for(int j=1; j<=n; ++j) d[i][j]=INF;
 93         }
 94         dfs(0);
 95         int res=INF;
 96         for(int i=k; i<=n; ++i) res=min(res,d[0][i]);
 97         printf("%d\n",res);
 98     } 
 99     return 0;
100 }

 

posted @ 2016-02-28 15:22  WABoss  阅读(250)  评论(0编辑  收藏  举报