zoukankan      html  css  js  c++  java
  • hdu 3996

    最大权闭合图,建议和我一样不知道这个模型的acmer搜一下——20077.型》。下面我就谈一下我对最大权闭合图的理解。知道了最大权闭合图的模型后,此题可看做是求最大权闭合图。首先,原图是一些有着权值的点,那么目的就是在这些点中选择一些点,但选一个点i,必须选择它的前提条件的所有点,那么怎么选才能符合这一限制条件呢。那么在点i和i的前提条件的所有点之间连接一条有向边表示有联系。那么现阶段的问题就转换成了在刚建好的图中选择闭合子图,这一闭合图中的点就是要选择的点。然后因为要求权值最大,最终转换成了最大权闭合子图。然后就是最大权闭合子图怎么求。注意到最后所有的点就只有两种可能,选或者没有选。发现这和网络流中的割有联系,因为一个割就是把网络流中的点分成了两类。增加源点s和汇点t,在s和正权值的点之间连一条有向边,容量为权值。在负权值和t之间为一条边容量为权值的相反数。这样得到的网络流的一个割中不含有点集中的联系边的割就是一个选择(选出来的点构成闭合子图)方案,其中s集合是选择了的点,t集合中是没选的点。现在使联系两点的边的权值为无穷大。那么此网络流得到的最小割的s集合就是最大权闭合子图选定的点集。首先,联系两点的边注意是有向的)肯定不会在最小割中,就意味着只要i点选了,那么它的前提点也一定选了,反之却不一定,满足了闭合着一性质。然后,最大权就是正权之和-最小割容量。先认为所有正权点都被选了。对于正权点,s到他的边如果是是割,说明他没被选,那么得减去这条边的容量。对于负全点,如果到t的边是割,那么说明他被选了,所以因为他是负权,所以得减去他到t的容量。最后得到的就是结果。

    #include <iostream>
    #include <cstdio>
    #include <queue>
    #include <cstring>
    using namespace std;
    const int maxn=2600;
    const int inf=200000000;
    const long long inf2=0x3f3f3f3f3f3f3f3fLL;
    struct Edge
    {
    	int from,to,next;
    	long long flow,cap;
    };
    Edge e[maxn*60*2];
    int head[maxn],map[110][30],cur[maxn],d[maxn],rel[maxn][55][2],gap[maxn],p[maxn];
    long long cost[maxn];
    int	tot,num,s,t;
    long long totg;
    void addedge(int from,int to,long long cap)
    {
    	e[tot].from=from;e[tot].to=to;e[tot].flow=0;e[tot].cap=cap;
    	e[tot].next=head[from];head[from]=tot;tot++;
    	e[tot].from=to;e[tot].to=from;e[tot].flow=0;e[tot].cap=0;
    	e[tot].next=head[to];head[to]=tot;tot++;
    }
    long long  augment()
    {
    	int x=t;
    	long long a=inf2;
    	while(x!=s)
    	{
    		a=min(a,e[p[x]].cap-e[p[x]].flow);
    		x=e[p[x]].from;
    	}
    	x=t;
    	while(x!=s)
    	{
    		e[p[x]].flow+=a;
    		e[p[x]^1].flow-=a;
    		x=e[p[x]].from;
    	}
    	return a;
    }
    long long maxflow()
    {
    	long long flow=0;
    	memset(gap,0,sizeof(gap));
    	memset(d,0,sizeof(d));
    	gap[0]=t+1;
    	int x=s;
    	memcpy(cur,head,(t+1)*sizeof(int));
    	while(d[s]<=t+1-1)
    	{
    		if(x==t)
    		{
    			flow+=augment();
    			x=s;
    		}
    		int ok=0;
    		for(int i=cur[x];i!=-1;i=e[i].next)
    		{
    			if(e[i].cap>e[i].flow&&d[x]==d[e[i].to]+1)
    			{
    				p[e[i].to]=i;
    				ok=1;
    				cur[x]=i;
    				x=e[i].to;
    				break;
    			}
    		}
    		if(!ok)
    		{
    			int m=t+1-1;
    			for(int i=head[x];i!=-1;i=e[i].next)
    			{
    				if(e[i].cap>e[i].flow) m=min(m,d[e[i].to]);
    			}
    			if(--gap[d[x]]==0) break;
    			gap[d[x]=m+1]++;
    			cur[x]=head[x];
    			if(x!=s) x=e[p[x]].from;
    		}
    	}
    	return flow;
    }
    int main()
    {
    	int amount,whe=0;
    	cin>>amount;
    	while(amount--)
    	{
    		whe++;
    		memset(head,-1,sizeof(head));
    		memset(rel,-1,sizeof(rel));
    		tot=0;num=1;s=0;totg=0;
    		int x,i,j,nlay,cos,val,fir,loc,ran,goldn,k;
    		scanf("%d",&nlay);
    		for(i=1;i<=nlay;i++)
    		{
    			scanf("%d",&goldn);
    			for(j=1;j<=goldn;j++,num++)
    			{
    				map[i][j]=num;
    				scanf("%d%d%d",&cos,&val,&fir);
    				cost[num]=val-cos;
    				if((val-cos)>0) totg+=(val-cos);
    				for(k=0;k<fir;k++)
    				{
    					scanf("%d%d",&loc,&ran);
    					rel[num][k][0]=loc;rel[num][k][1]=ran;
    				}
    			}
    		}
    		t=num;
    		int tl,tr;
    		for(i=1;i<=t-1;i++)
    		{
    			if(cost[i]>0) addedge(s,i,cost[i]);
    			else addedge(i,t,-cost[i]);
    			k=0;
    			while(rel[i][k][0]!=-1)
    			{
    				addedge(i,map[rel[i][k][0]][rel[i][k][1]],inf2);
    				k++;
    			}
    		}
    		printf("Case #%d: %I64d\n",whe,totg-maxflow());
    	}
    	return 0;
    }
    


  • 相关阅读:
    jboss:在standalone.xml中设置系统属性(system-properties)
    心得体悟帖---200608(机会都是自己创造的)
    心得体悟帖---200608(易中天评三国之刘备和诸葛亮关系启示:诚意真的重要)
    算法与数据结构---6.1、斐波那契数列-递推解法
    算法与数据结构---5、递推
    C++指针相关问题
    C++ new一个数组
    指针数组和数组指针的区别
    C++ new的用法
    webdings 和 wingdings 字体
  • 原文地址:https://www.cnblogs.com/lj030/p/3002287.html
Copyright © 2011-2022 走看看