zoukankan      html  css  js  c++  java
  • 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
    ",res);
     98     } 
     99     return 0;
    100 }
  • 相关阅读:
    Python里的目录方法
    PythonFile对象的属性
    Python read和write方法
    Python打开和关闭文件
    Python打印到屏幕_读取键盘输入
    Python包
    Python globals和locals函数_reload函数
    Python dir( )函数
    【C 语言】一元二次方程
    【C语言】已知三角形三边长,求三角形面积
  • 原文地址:https://www.cnblogs.com/WABoss/p/5224827.html
Copyright © 2011-2022 走看看