zoukankan      html  css  js  c++  java
  • 深入理解最小割的意义

    在做网络流题目的时候,我们时常因为无法正确建图而遗憾错过本应该的AC。

    今天通过一些题目,我好好记录一下自己对最大流、最小割的学习感受。

    Hdu 1565,题意:

    给你一个矩阵,矩阵上每个点上都有一个数字,现在要你在矩阵中取一些数字,使得取得的数字和最大!

    规则:相邻的格子不能同时取,即取了一个以后,它四周的数字便不能再取了。

    分析:(题目实际就是求一个无向图的最大点权独立集)

    这种方格的题目,我们最容易想到二分图,最大流等等。事实上,也确实是用最大流来解二分图。首先建图:我们将行列相加为奇数的点与S相连,容量就为该点的点权,行列相加为偶数的点与T相连,容量同样为该点的点权。然后,所有与S相连的点,将它与它四周连一条边,容量为无穷大。对这样的图求一次最大流,最大流的值即该图的最小点集覆盖,我们最后用所有点权和减去最大流便是我们的答案了(最大点权独立集=所有点权-最小点权覆盖集)

    图是这样建好了,可是我们会问,为什么就要这样建图呢?为什么某个点向它四周的点的边容量就要是无穷大?

    其实是这样的:求完最大流以后,其实就形成了一个最小割。最小割将图分成了两部分。而这个最小割的几何意义是,完成一次取数方案的最小花费!

    我们对残留图进行遍历,对于左边那些点,依然与S相连的点,说明它最终被取了,没有相连的点,即被割了,说明它最终没有被取。我们可以想象,如果某个与S相连的点的边被割了,那么它四周与T相连的那些点与T形成的边便一定被保留了,也就是说想要保留某一个,就必须割去这个点对应的另一边,而最小割割的又恰好是较小的,于是较大的那一个便得到了保存。也可以理解为,割的那条边便是花费,我花费叫小的钱,用来保留较大的点。再看,题目要求某一个点不能与它四周的点同时被取,那么我们就将他们连一条无穷大的边,这样的话,如果这条边的两点都要被取的话(一个与S连,一个与T连),我们就要付出无穷大的代价,这么贵,当然不会取了。

    再来看一题HDU 3657,这是2010年成都赛区网赛上的一道题

    题意:还是给你一个矩阵,矩阵上有一些数,依然是叫你取数,如果某两个相邻的数被你取了,那么你取得的成绩将会减去某一个代价。也就是说,相邻的点可以取了,只是要额外支付一些代价。并且,还会给你一些点,这些点必须要取到。问你最后取到的最大值。

    分析:

    依然是二分图的最小割,最后左边与S相连的点说明最终被取到,右边与T相连的点说明最终被取到了。我们先关注一下题目要求一定要取的点,怎么保证最小割一定不会割这些点呢,你可能已经想到了,我们将它与相应的S或者T连无穷大的边,那么最小割就一定不敢割它了。好了,再来处理一下相邻点的问题,上一题中,我们是要求不能取相邻的点,所以我们将他们的边值设为了无穷大,也就是要去他们两个,就必须割断这条边,而割断这条边的话,付出无穷大的代价而已。现在题目要求不是不能取了,只是要付出一些代价,怎么样,想到了什么?是不是将无穷大该成题目要求的代价就OK了?回答是对的!

    现在我们建图:

    所有行列相加为偶数的点与S相连,所有行列相加为奇数的点与T相连,容量都为他们相应的点权。对于与S相连的所有点,他们向四周连一条代价为2*(x&y)的边,x与y分别为连点的点权。好了,求最大流,最后输出所有点权减去最大流值。

    下面是第二题的代码

    #include<iostream>
    #include<string>
    #include<queue>
    using namespace std;
    #define inf 0xfffffff
    #define min(a,b) a<b?a:b
    
    typedef struct node
    {
    	int v;
    	int f;
    	struct node *next;
    }node;
    
    node *link[3000];
    node edge[20000];
    int num,S,T,n,m,l,N;
    int map[51][51];
    int di[4][2]={1,0,0,1,-1,0,0,-1};
    
    void add(int u,int v,int f)
    {
    	edge[num].v=v;
    	edge[num].f=f;
    	edge[num].next=link[u];
    	link[u]=edge+num++;
    	edge[num].v=u;
    	edge[num].f=0;
    	edge[num].next=link[v];
    	link[v]=edge+num++;
    }
    
    int h[3000],vh[3000];
    
    int find(int u,int FLOW)
    {
    	if(u==T)
    		return FLOW;
    	int left=FLOW;
    	int temp=N-1;
    	for(node *p=link[u];p;p=p->next)
    	{
    		if(p->f && h[u]==h[p->v]+1)
    		{
    			int MIN=min(p->f,left);
    			int f=find(p->v,MIN);
    			left-=f;
    			p->f-=f;
    			edge[(p-edge)^1].f+=f;
    			if(!left || h[S]==N)
    				return FLOW-left;
    		}
    		if(p->f && h[p->v]<temp)
    			temp=h[p->v];
    	}
    	if(FLOW==left)
    	{
    		vh[h[u]]--;
    		if(!vh[h[u]])
    		{
    			h[S]=N;
    		}
    		else
    		{
    			h[u]=temp+1;
    			vh[h[u]]++;
    		}
    	}
    	return FLOW-left;
    }
    
    int sap()
    {
    	int ans=0;
    	N=T+1;
    	memset(vh,0,sizeof(vh));
    	memset(h,0,sizeof(h));
    	vh[0]=N;
    	while(h[S]<N)
    	{
    		ans+=find(S,inf);
    	}
    	return ans;
    }
    
    int main()
    {
    	int i,j,k,a,b,sum;
    	freopen("D:\\in.txt","r",stdin);
    	while(scanf("%d%d%d",&n,&m,&l)!=EOF)
    	{
    		S=0; T=n*m+1; sum=0;
    		memset(link,0,sizeof(link));
    		num=0;
    		for(i=1;i<=n;i++)
    		{
    			for(j=1;j<=m;j++)
    			{
    				scanf("%d",&map[i][j]);
    				sum+=map[i][j];
    			}
    		}
    		for(i=1;i<=n;i++)
    		{
    			for(j=1;j<=m;j++)
    			{
    				if((i+j)%2==0)
    				{
    					add(S,(i-1)*m+j,map[i][j]);
    					for(k=0;k<4;k++)
    					{
    						a=i+di[k][0];
    						b=j+di[k][1];
    						if(a>=1 && a<=n && b>=1 && b<=m)
    						{
    							add((i-1)*m+j,(a-1)*m+b,2*(map[i][j]&map[a][b]));
    						}
    					}
    				}
    				else
    				{
    					add((i-1)*m+j,T,map[i][j]);
    				}
    			}
    		}
    		for(i=0;i<l;i++)
    		{
    			scanf("%d%d",&a,&b);
    			if((a+b)%2==0)
    			{
    				add(S,(a-1)*m+b,inf);
    			}
    			else
    			{
    				add((a-1)*m+b,T,inf);
    			}
    		}
    		cout<<sum-sap()<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    网页特殊符号HTML代码大全
    检测手机类型正则表达式
    blur和focus的运用
    腾讯对外分享组件接口文档
    js 类型检测
    iconfont的应用
    运算符优先级 (JavaScript)
    IOC(控制反转)和DI(依赖注入)
    Mybatis的运行原理
    通用Mapper
  • 原文地址:https://www.cnblogs.com/ka200812/p/2123240.html
Copyright © 2011-2022 走看看