首页 > 代码库 > POJ 3345——Bribing FIPA(树形DP)
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; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。