題目大意:
一個國家想賄賂至少m個國家,給出賄賂每個國家需要的錢及他們的附屬關係。如果賄賂了主國,其附屬國家也同樣視爲被賄賂了,且保證關係網沒環,和一個國家最多隻能被一個國家控制。
題目思路:本題要用到樹形揹包和字符串處理,字符串用普通方法讀入特別麻煩且代碼繁瑣。這裏我第一次用到了map:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
using namespace std;
map<string,int>a;//定義map(下標爲字符串方便操作)
int u[205],f[205],m[205][205],d[205][205],n,o,t[205];
char h[205],r[205];
int dfs(int x){//深搜
int i,j,k;
int ans=1;
if(x==0)ans=0;
if(u[x]==1&&x>0){
d[x][0]=0;
d[x][1]=f[x];
return 1;
}
for(i=1;i<=n;i++)
if(m[x][i]==0)
ans+=dfs(i);//將結果相加
d[x][0]=0;
for(i=1;i<=n;i++){
if(m[x][i]==-1) continue;
for(k=n;k>=0;k--)//揹包
for(j=1;j<=k;j++){
if(d[x][k-j]!=-1&& d[i][j]!=-1){
if(d[x][k]!=-1)
d[x][k]=min(d[x][k],d[x][k-j]+d[i][j]);
else
d[x][k]=d[x][k-j]+d[i][j];
}
}
}
if(d[x][ans]==-1||d[x][ans]>f[x])
d[x][ans]=f[x];
return ans;
}
int lily(){//因爲有可能是'#'所以字符讀入
char c=getchar();
int s=0;
while(c<'0'||c>'9')
{
if(c=='#')return 0; //當爲'#'時返回'0';
c=getchar();
}
while(c>='0'&&c<='9')
{
s*=10;
s+=c-'0';
c=getchar();
}
return s;
}
int main(void){
int i,j,k,g;
char c;
while(1){
n=lily();//讀入n
if(n==0)break;//當n爲'0'結束
scanf("%d",&o);
memset(m,-1,sizeof(m));
memset(t,0,sizeof(t));
getchar();
k=1;
for(i=1;i<=n;i++){//記錄
scanf("%s",h);
scanf("%d",&g);
if(!a[h])
a[h]=k++;
f[a[h]]=g;
u[a[h]]=1;
c=getchar();
while(c!='\n'){
scanf("%s",r);
if(!a[r]){
a[r]=k++;
}
m[a[h]][a[r]]=0;
t[a[r]]++;
u[a[h]]++;
c=getchar();
}
}
f[0]=0;
u[0]=1;
for(i=1;i<=n;i++){
if(t[i]==0){
m[0][i]=0;
u[0]++;
f[0]+=f[i];
}
}
memset(d,-1,sizeof(d)); //清空
dfs(0);//搜索
int max=10000000;
for(j=o;j<=n;j++){
if(d[0][j]!=-1 &&d[0][j]<max){
max=d[0][j];
}
}
printf("%d\n",max);//輸出
a.clear();//清空
}
return 0;
}