hdu2415(树上背包)

这道题好像没什么人写题解,于是写了一发

题意:有个坏蛋想要参加竞选,需要得到m个人的支持,买通第i个人(1<=i<=n)需要一个cost[i],同时这些人又有上下属关系,只要买通了领导,他的下属(可以是下属的下属)也会给你投票,问最少要花多少钱

数据范围:N<=200,m<=n;

其实就是比较裸的树上分组背包,每个子节点的背包是一个组,选自己也是一个组,dfs搞一搞就好了,然而字符串处理实在恶心.....

#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
using namespace std;
const int MAX=1<<29;
int n,m;
map<string,int>dui;
vector<int>arr[205];
char str[100005],tmp[105];
int dp[205][205],fa[205],siz[205],cost[205],cnt=0;
void dfs1(int now)
{
    int i,j;
    siz[now]=1;
    for(i=0;i<arr[now].size();i++)
    {
        int v=arr[now][i];
        dfs1(v);
        siz[now]+=siz[v];
    }
}
void dfs(int now)
{
    int i,j,k;
    for(i=0;i<arr[now].size();i++)
    {
        dfs(arr[now][i]);
        int v=arr[now][i];
        for(j=m;j>=1;j--)for(k=1;k<=j;k++)dp[now][j]=min(dp[now][j],dp[now][j-k]+dp[v][k]);
    }
    if(now!=n+1)for(i=1;i<=min(m,siz[now]);i++)dp[now][i]=min(cost[now],dp[now][i]);
    return ;
}
int main()
{
    int i,j;
    char ss[10];
    while(scanf("%s",ss)!=EOF)
    {
        n=0;
        cnt=0;
        if(ss[0]=='#')return 0;
        for(i=0;i<strlen(ss);i++)n*=10,n+=ss[i]-'0';
        scanf("%d",&m);
        int i,j;
        for(i=0;i<=n+1;i++)arr[i].clear();
        dui.clear();
        getchar();
        for(i=1;i<=n+1;i++)fa[i]=i;
        for(i=0;i<n;i++)
        {
            gets(str);
            int len=strlen(str);
            for(j=0;j<len;j++)if(str[j]==' ')break;
            int pos=j;
            memset(tmp,0,sizeof(tmp));
            for(j=0;j<pos;j++)tmp[j]=str[j];
            string a=tmp;
            if(!dui[a])dui[a]=++cnt;
            int name1=dui[a],costs=0;
            while(str[pos]>'9'||str[pos]<'0')pos++;
            for(j=pos;;j++)
            {
                if(str[j]=='\0'||str[j]>'9'||str[j]<'0')
                {
                    pos=j;
                    break;
                }
                costs*=10;
                costs+=str[j]-'0';
            }
            cost[name1]=costs;
            int nums=0;
            string b;
            for(j=pos+1;j<len;j++)
            {
                if(str[j]!=' ')
                {
                    tmp[nums++]=str[j];
                    if(str[j+1]==' '||str[j+1]=='\0')
                    {
                        tmp[nums++]='\0';
                        b=tmp;
                        nums=0;
                        if(!dui[b])dui[b]=++cnt;
                        int name2=dui[b];
                        arr[name1].push_back(name2);
                        fa[name2]=name1;
                    }
                }
            }
        }
        for(i=1;i<=n+1;i++)
        {
            dp[i][0]=0;
            for(j=1;j<=m;j++)dp[i][j]=MAX;
        }
        for(i=1;i<=n;i++)if(fa[i]==i)arr[n+1].push_back(i);
        dfs1(n+1);
        dfs(n+1);
        printf("%d\n",dp[n+1][m]);
    }
}
/*
9 5
A 45 B C
B 20
C 30
D 60 E F
E 20
F 50 G H
G 10
H 25 I
I 15
*/

 

转载于:https://www.cnblogs.com/sylsyl/p/7144889.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值