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 }