POJ-3345 Bribing FIPA 树形DP+分组背包
题目链接:http://poj.org/problem?id=3345
国家之间可能存在依赖关系,可以求出每个国家向下的每种情况的最优消费,即f[u][i]表示节点为u时选择i个国家的最优消费。自底向上更新时就是分组背包问题了:
f[u][i]=Min{ f[u][i],f[u][i-j]+f[v][j] | v为u的儿子节点,0<=j<=v子树的节点数 },其实本来是3维的,不过这里用滚动数组优化了。
1 //STATUS:C++_AC_16MS_588KB 2 #include<stdio.h> 3 #include<stdlib.h> 4 #include<string.h> 5 #include<math.h> 6 #include<iostream> 7 #include<string> 8 #include<algorithm> 9 #include<vector> 10 #include<queue> 11 #include<stack> 12 #include<map> 13 using namespace std; 14 #define LL __int64 15 #define pii pair<int,int> 16 #define Max(a,b) ((a)>(b)?(a):(b)) 17 #define Min(a,b) ((a)<(b)?(a):(b)) 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 #define lson l,mid,rt<<1 20 #define rson mid+1,r,rt<<1|1 21 const int N=300,INF=0x3f3f3f3f,MOD=100000000; 22 const double DNF=100000000000; 23 24 struct Edge{ 25 int u,v; 26 }e[N]; 27 28 int first[N],next[N],vis[N],f[N][N],cost[N],cnt[N]; 29 int n,m,mt; 30 31 void adde(int u,int v) 32 { 33 e[mt].u=u,e[mt].v=v; 34 next[mt]=first[u],first[u]=mt++; 35 } 36 37 void dfs(int u) 38 { 39 int i,j,v,k; 40 f[u][0]=0; 41 i=first[u]; 42 if(i==-1){ 43 f[u][1]=cost[u]; 44 cnt[u]=1; 45 return; 46 } 47 for(;i!=-1;i=next[i]){ 48 dfs(e[i].v); 49 cnt[u]+=cnt[e[i].v]; 50 for(v=cnt[u];v>=0;v--){ 51 for(j=0;j<=v;j++){ 52 f[u][v]=Min(f[u][v],f[u][v-j]+f[e[i].v][j]); 53 } 54 } 55 } 56 f[u][++cnt[u]]=cost[u]; 57 } 58 59 int main() 60 { 61 // freopen("in.txt","r",stdin); 62 int i,j,a,k,kt,ans,id,idfa; 63 char s[110],cs[N*110]; 64 map<string,int> q; 65 while(gets(s)) 66 { 67 if(s[0]=='#')break; 68 q.clear(); 69 mem(first,-1); 70 mem(f,INF); 71 mem(vis,0);mem(cnt,0); 72 mt=0; 73 ans=INF; 74 sscanf(s,"%d%d",&n,&m); 75 for(i=1,id=0;i<=n;i++){ 76 scanf("%s%d",s,&a); 77 if(!q[s])q[s]=++id; 78 idfa=q[s]; 79 cost[idfa]=a; 80 gets(cs); 81 if(!cs[0])continue; 82 for(k=1,j=0;1;k++,j++){ 83 if(cs[k]==' ' || cs[k]=='\0'){ 84 s[j]='\0'; 85 if(!q[s])q[s]=++id; 86 kt=q[s]; 87 vis[kt]=1; 88 adde(idfa,kt); 89 j=-1; 90 if(cs[k]=='\0')break; 91 } 92 else s[j]=cs[k]; 93 } 94 } 95 for(i=1;i<=n;i++){ 96 if(vis[i])continue; 97 adde(0,i); 98 } 99 100 dfs(0); 101 for(i=m;i<=n;i++) 102 if(f[0][i]<ans)ans=f[0][i]; 103 104 printf("%d\n",ans); 105 } 106 return 0; 107 }