您的位置:首页 > 其它

POJ3345 Bribing FIPA(树形DP)

2016-06-15 09:33 197 查看
题目大意:

一个国家想贿赂至少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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp poj