题意:一个国家想贿赂至少m个国家,给出贿赂每个国家需要的钱及他们的附属关系。如果贿赂了主国,其从属国家也同样视为被贿赂了,且关系网无环。
题解:树形DP,dp[now][i]为以第now国家为子树的国家团体贿赂了i个国家所需要的最小花费,在建立一个虚拟结点0,让它与所有主国建立一条边。
View Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<map> 5 #include<string> 6 using namespace std; 7 map<string,int> MP; 8 const int inf=0x3f3f3f3f; 9 int dp[300][300],tot[300],val[300],head[300],nc,n,m; 10 bool vis[300]; 11 struct Edge 12 { 13 int to,next; 14 }edge[300*300]; 15 void add(int a,int b) 16 { 17 edge[nc].to=b;edge[nc].next=head[a];head[a]=nc++; 18 } 19 void dfs(int now) 20 { 21 vis[now]=true; 22 dp[now][0]=0; 23 tot[now]=0; 24 for(int i=head[now];i!=-1;i=edge[i].next) 25 { 26 int to=edge[i].to; 27 if(!vis[to]) 28 dfs(to); 29 int num=tot[to],all=tot[now]+tot[to]; 30 tot[now]=all; 31 for(int i=all;i>=1;i--) 32 { 33 for(int j=0;j<=num&&j<=i;j++) 34 { 35 dp[now][i]=min(dp[now][i],dp[now][i-j]+dp[to][j]); 36 } 37 } 38 } 39 dp[now][++tot[now]]=val[now]; 40 } 41 int main() 42 { 43 char s[100000]; 44 while(gets(s),strcmp(s,"#")!=0) 45 { 46 sscanf(s,"%d%d",&n,&m); 47 memset(head,-1,sizeof(head)); 48 memset(vis,false,sizeof(vis)); 49 memset(val,0,sizeof(val)); 50 memset(dp,0x3f,sizeof(dp)); 51 nc=0;MP.clear(); 52 int num=0; 53 for(int i=1,j,k,id;i<=n;i++) 54 { 55 gets(s); 56 char tp[100]; 57 for(j=0;s[j]!=' ';j++); 58 s[j]='\0'; 59 strcpy(tp,s); 60 for(++j,k=0;s[j]!='\0'&&s[j]!=' ';j++) 61 k=k*10+s[j]-'0'; 62 if(MP.find(tp)==MP.end()) 63 id=MP[tp]=++num; 64 else 65 id=MP[tp]; 66 val[id]=k; 67 if(s[j]=='\0') 68 continue; 69 else 70 { 71 for(k=++j;s[j]!='\0';j++) 72 { 73 if(s[j]==' ') 74 { 75 s[j]='\0'; 76 strcpy(tp,s+k); 77 if(MP.find(tp)!=MP.end()) 78 add(id,MP[tp]); 79 else 80 add(id,MP[tp]=++num); 81 vis[MP[tp]]=true; 82 k=j+1; 83 } 84 } 85 if(s[k]!=' '&&s[k]!='\0') 86 { 87 strcpy(tp,s+k); 88 if(MP.find(tp)!=MP.end()) 89 add(id,MP[tp]); 90 else 91 add(id,MP[tp]=++num); 92 vis[MP[tp]]=true; 93 } 94 } 95 } 96 val[0]=inf; 97 for(int i=1;i<=num;i++) 98 if(!vis[i]) 99 add(0,i); 100 memset(vis,false,sizeof(vis)); 101 dfs(0); 102 int ans=inf,len=tot[0]; 103 for(int i=m;i<len;i++) 104 ans=min(ans,dp[0][i]); 105 printf("%d\n",ans); 106 } 107 return 0; 108 }