题意:一个国家想贿赂至少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 }