POJ3345 Bribing FIPA(树形DP)

39 篇文章 0 订阅
32 篇文章 0 订阅

题目大意:

一个国家想贿赂至少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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值