POJ 3345——Bribing FIPA(树形DP)

题目分析:

现在有n个村子,你想要用收买m个国家为你投票,其中收买第i个国家的代价是val[i]。但是有些国家存在从属关系,如果B从属于A国,则收买了A也意味着买通了B,而且这些关系是传递的。问你最小要付出的代价是多少?

这题的难点在于怎么建图,弱菜不会,只能膜拜大神的代码,然后自己捉摸着敲,dfs部分就和一般的树形DP+背包差不多,只是状态的初始化有些变化

建图需要加个超级根,连接大国(小国和大国是从属关系)

dp [ i ] [ j ]表示以 i 为根取得 j 票所需要的最小费用

大牛用了map,今天看了下map的基础知识,涨姿势啦

贴上辛辛苦苦AC的代码,(我喜欢A,喜欢后面加个C或者加个V,但是不喜欢前面加个W)

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
#define inf 0x3f3f3f3f
#define M 210
#define ms(s,i) memset(s,i,sizeof(s))
using namespace std;
typedef map<string,int> msi;
struct pp{int v,w,next;}edge[M*2];int head[M],tot,root,n,m;
inline void addedge(int u,int v,int w,int *h){edge[tot].v=v,edge[tot].w=w,edge[tot].next=h[u],h[u]=tot++;}
int dp[210][210],vis[210],w[210],fa[210],num[210];
msi mp;
void dfs(int u)
{
    vis[u]=1;
    dp[u][0]=0;
    num[u]=1;                                        //统计父亲节点有多少个儿子
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(vis[v]) continue;
        dfs(v);
        num[u]+=num[v];
        for(int k=num[u];k>=1;--k){                //儿子能取得的票数
            for(int j=0;j<=k&&j<=num[v];++j){       //在票数里挑选最优
                dp[u][k]=min(dp[u][k],dp[u][k-j]+dp[v][j]); //01背包
            }
        }
    }
    dp[u][num[u]]=w[u]; //
    return;
}
int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    char s[1000];
    while(gets(s)){
        if(s[0]=='#') break;
        sscanf(s,"%d %d",&n,&m);
        tot=0,mp.clear(),ms(dp,0x3f),ms(vis,0),ms(fa,0),ms(head,-1),ms(num,0);
        int id=0;
        for(int i=1;i<=n;++i){
            scanf("%s",s);
            if(mp.find(s)==mp.end()){
                mp[s]=++id;
            }
            int u=mp[s];
            scanf("%d",&w[u]);
            while(getchar()!='\n'){
                scanf("%s",s);
                if(mp.find(s)==mp.end()){
                    mp[s]=++id;
                }
                addedge(u,mp[s],0,head);
                fa[mp[s]]=1;
            }
        }
        for(int i=1;i<=n;++i){
            if(!fa[i]) addedge(0,i,0,head);
        }
        w[0]=0;
        dfs(0);
        int ans=inf;
        for(int i=m;i<=n;++i){
            if(dp[0][i]<ans) ans=dp[0][i];
        }
        cout<<ans<<endl;
    }
    return 0;
}

POJ 3345——Bribing FIPA(树形DP)

时间: 2024-08-29 05:29:38

POJ 3345——Bribing FIPA(树形DP)的相关文章

poj 3345 Bribing FIPA 【树形dp + 01背包】

Bribing FIPA Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4274   Accepted: 1337 Description There is going to be a voting at FIPA (Fédération Internationale de Programmation Association) to determine the host of the next IPWC (Interna

poj 2324 Anniversary party(树形DP)

/*poj 2324 Anniversary party(树形DP) ---用dp[i][1]表示以i为根的子树节点i要去的最大欢乐值,用dp[i][0]表示以i为根节点的子树i不去时的最大欢乐值, ---于是当i去时,i的所有儿子都不能去:dp[i][1]=sum(dp[j][0])+a[i],其中j是i的儿子节点. ---当i不去时,i的儿子可去也可不去:dp[i][0]=sum(max(dp[j][0],dp[j][1])),j是i的儿子节点 ---边界条件:当i时叶子节点时,dp[i][

[POJ 1947]Rebuilding Roads (树形dp)

题目链接:http://poj.org/problem?id=1947 题目大意:给你一棵树,树上N个节点.问最少拆掉多少条边使得存在一个联通块,有P个节点. 树形dp,设计状态:dp[u][i]代表以u为根节点的剩下i个节点最少需要拆掉多少条边. 状态转移:dp[u][i+j] = min(dp[u][i+j],dp[u][i]+dp[v][j]-1); 其中v是u的儿子节点. 相当于在树上跑01背包,即每个儿子节点去掉剩下j个的但是要连上u-v边,或者不去掉剩下j个的. 代码: 1 impo

POJ 1947 Rebuilding Roads (树形dp 经典题)

Rebuilding Roads Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 9499   Accepted: 4317 Description The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The

POJ - 3162 Walking Race 树形dp 单调队列

POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这样的区间最长的长度? 一开始楞是没看懂题意,最讨厌这种四级题,这是在刁难我英语小能手(能用翻译的就不自己动手).而且这题感觉单调队列那里的处理更难一点,不过还是来说一说怎么树形dp取得最远距离,先画个简简单单丑丑的图 我们直接从1作为根节点开始dfs的话,可以处理1的最远距离,并且可以得出到其它节点

POJ 3162 Walking Race 树形DP+线段树

给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成为一段长度为n的数列 现在mm想要从这数列中选出一个连续的区间,要求这个区间的max-min<=m 输出最长的区间 做了一个下午 思路: 分成2个部分: 1.求出数列,即对于一棵树,求出每一个节点能到达的最远距离 2.对于这段数列,选出一个区间,使得区间的max-min<=m,并且使得区间长度尽量

POJ 2152 Fire (树形DP,经典)

题意:给定一棵n个节点的树,要在某些点上建设消防站,使得所有点都能够通过某个消防站解决消防问题,但是每个点的建站费用不同,能够保证该点安全的消防站的距离上限也不同.给定每个点的建站费用以及最远的消防站距离上限,求保证该树安全的最小花费. 思路: 要选择部分点来建站解决消防问题,而总花费是有最优解的. 如何进行树形DP? 假设某点t的所有子树的消防问题都解决,而且已经获得最优解了,那么现在考虑的是点t的最优解问题,点t可以依靠任何点只要不超过距离限制即可,那枚举一下所有点试试,一旦t依靠某个点j解

POJ 2486 Apple Tree 树形DP+分组背包

链接:http://poj.org/problem?id=2486 题意:一棵(苹果)树,树上有N个结点(N<=100),起点是结点1.每个结点上有若干个苹果,我可以进行K步操作(K<=200),每次操作是从当前结点移动到相邻的结点,并且到了相邻的结点以后会吃掉上面的所有苹果并且苹果不再长出来,相邻是指两个结点之间有边相连.问在K步操作之后最多可以吃掉多少个苹果. 思路:刚入手的时候觉得是一般的树形背包问题,dp[i][j]代表的是以i为根的子树中走j个结点所能吃到的苹果数,来进行状态转移,但

POJ 2342 Anniversary party 树形dp入门

http://poj.org/problem?id=2342 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知每个人的活跃指数和上司关系(当然不可能存在环),求邀请哪些人(多少人)来能使得晚会的总活跃指数最大. 对于每一个人,都有两种情况,选,或者不选.然后选了后,他的下属就只能不选了,如果它不选,下属可能选或者不选. 这样用dfs + 记忆化搜索,就好了 每次搜索,就是要求以第cur个节点为根的子树中,其中第cur个节点的状态是s