zoukankan      html  css  js  c++  java
  • poj 3345

    树形DP,f(i,j)表示i节点及其子树得到j个国家所需的最小贿赂,对于j==i子树的节点总数sum,所需的最小费用肯定就是i节点本身的cost,对于j<sum的情况,肯定只有在其子树中选,如果选了i就是把整个子树都选了,然后,这个过程用的是01背包的思想,不知道这个词用的 恰不恰当,但想清楚,这个DP过程就可以了,对每个i的子树,恩。

    //思路来啦
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define mem(a,b) memset(a,b,sizeof(a))
    #define min(a,b) ((a)<(b)?(a):(b))
    using namespace std;
    const int maxn=200+30;
    int inf=0x3f3f3f3f;
    char Map[maxn][110];
    int f[maxn][maxn],g[maxn][maxn],head[maxn],e[maxn],next[maxn],vis1[maxn],vis2[maxn];
    int cost[maxn],qn[maxn];
    int n,m,tot,qe;
    int getL(char *s)
    {
    	int i;
    	for(i=0;i<tot;i++)
    		if(strcmp(s,Map[i])==0) return i;
    	strcpy(Map[tot++],s);
    	return tot-1;
    }
    void dp(int u)
    {
    	int i,j,k,v,p;
    	if(!vis2[u])
    	{
    		f[u][0]=0;
    		f[u][1]=cost[u];
    		qn[u]=1;
    		return;
    	}
    	qn[u]=0;
    	f[u][0]=0;
    	for(i=head[u];i!=-1;i=next[i])
    	{
    		dp(e[i]);
    		qn[u]+=qn[e[i]];
    	}
    	qn[u]++;
    	mem(g,inf);
    	g[0][0]=0;
    	int sum=0;
    	for(i=head[u],j=1;i!=-1;i=next[i],j++)//01背包的思路
    	{
    		v=e[i];
    		sum+=qn[v];
    		for(k=0;k<=sum;k++)
    		{
    			for(p=0;p<=qn[v];p++)
    			{
    				g[j][k]=min(g[j-1][k-p]+f[v][p],g[j][k]);
    			}
    		}
    	}
    	for(i=1;i<=sum;i++)
    		f[u][i]=g[j-1][i];
    	f[u][qn[u]]=cost[u];
    }
    int main()
    {
    	char s[101];
    	while(gets(s))
    	{
    		if(s[0]=='#') break;
    		sscanf(s,"%d %d",&n,&m);
    		tot=0;qe=0;
    		int i,loc,am,j,u,v;
    		mem(f,inf);
    		mem(head,-1);
    		mem(vis1,0);mem(vis2,0);
    		for(i=0;i<n;i++)
    		{
    			scanf("%s %d",s,&am);
    			u=getL(s);
    			cost[u]=am;
    			while(scanf("%c",s)&&s[0]!='\n')
    			{
    				vis2[u]=1;
    				scanf("%s",s);
    				v=getL(s);
    				vis1[v]=1;
    				next[qe]=head[u];
    				head[u]=qe;
    				e[qe++]=v;
    			}
    		}
    		for(i=0;i<n;i++)
    		{
    			if(!vis1[i]) 
    			{
    				next[qe]=head[n];
    				head[n]=qe;
    				e[qe++]=i;
    			}
    		}
    		vis2[n]=1;
    		cost[n]=inf;
    		dp(n);
    		int ans=inf;
    		for(i=m;i<=(qn[n]-1);i++) ans=min(ans,f[n][i]);
    		printf("%d\n",ans);
    	}
    	return 0;
    }



  • 相关阅读:
    数字IC笔试题 ——Cadence前端设计2018
    Verilog -- 序列检测器及其最小状态数
    Verilog -- 状态机
    数字IC笔试 -- 汇顶设计验证2018
    Systemverilog -- 数据类型
    深度学习资料
    Lucene介绍与使用
    java全角、半角字符的关系以及转换
    怎样用正则表达式去除文本中的标点符号
    linux下转换windows文件格式,启动脚本报错问题解决
  • 原文地址:https://www.cnblogs.com/lj030/p/3002210.html
Copyright © 2011-2022 走看看