poj openjudge 1036 gugle seating

传送门点击打开链接

题目大意 :给出n*m的矩阵,若矩阵该位置为1,则为一个人,若为2则为一台电脑,若为0,则为空地,求最大匹配人数。

(匹配的意思是如果一个人相邻有两台电脑,且这两台电脑不在同一行或者同一列,即人,两台电脑在矩阵中构成了‘L’型,则算一种匹配,一台电脑只能和一个人匹配。)

(n,m<=500)

 

思路:首先我们意识到一个人所匹配的电脑一定是不同行的,即不同奇偶,奇偶让我们想到了什么?二分图匹配,选一个匹配的过程就变成了选一个奇数行的电脑->选一个与该电脑相邻的人->再选一个与这个人相邻的偶数行的电脑….

所以我们就连上<s,odd,1>,<odd,person,1>,<preson,even,1>三种边,然后最大流跑就是了。

是吗?当然不是上面那样、

如果我们这样连边跑最大流,那么一个人可能会被用到两次?所以明显是错的!!!

(当时真的是wa死我了…..)。

怎么解决呢?我们这样连边:

<s,odd,1>,<odd,person_in,1>,<preson_in,preson_out,1>,<person_out,even,1>,<even,t,1>/

什么意思呢?我们将每个人拆成两个点,一个流入,一个流出,流入点和流出点连一条流量为1的边,就可以限制每个人只匹配一次了..(我居然连这个都没想到….)。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<ctime>
#define inf 1000000000
using namespace std;
struct edge{int to;int next;int flow;
};edge bian[5000010];
int size=1,first[3000010],head,tail,dis[3000010],p[5000010],s,t,n,m,A[550][550];
bool exist[3000010];
int pos1(int x,int y) {return (x-1)*m+y;}
int pos2(int x,int y) {return m*n+(x-1)*m+y;}
void inser(int x,int y,int z) {
	bian[++size].to=y;
	bian[size].next=first[x];
	bian[size].flow=z;
	first[x]=size;
	
	bian[++size].to=x;
	bian[size].next=first[y];
	bian[size].flow=0;
	first[y]=size;
}
bool bfs(int x,int y) {
	memset(dis,127,sizeof(dis));
	dis[x]=0;
    head=0,tail=1;p[1]=x;
    memset(exist,false,sizeof(exist));
    while(head!=tail)
    {
    	int k=p[++head];
    	exist[k]=false;
    	for(int u=first[k];u;u=bian[u].next) 
    	{
    		if(dis[bian[u].to]>=9000000&&bian[u].flow>0)
    		{
    			dis[bian[u].to]=dis[k]+1;
    			if(!exist[bian[u].to])
    			{
    				p[++tail]=bian[u].to;
    				exist[bian[u].to]=true;
    			}
    		}
    	}
    }
    return dis[y]<=9000000;
}
int dfs(int x,int F) {
	if(x==t) return F;
	int ret=0;
	for(int u=first[x];u&&F>0;u=bian[u].next)
	{
		if(bian[u].flow>0&&dis[bian[u].to]==dis[x]+1)
		{
			int f=dfs(bian[u].to,min(F,bian[u].flow));
			F-=f;
			bian[u].flow-=f;
			bian[u^1].flow+=f;
			ret+=f;
		}
	}
	if(F==0||ret==0) dis[x]=-5;
	return ret;
}
int maxflow(int x,int y) {
	int ret=0;
	while(bfs(x,y)) ret+=dfs(x,1000000000);
	return ret;
}
int main()
{
	freopen("gugleseating.in","r",stdin);
	freopen("gugleseating.out","w",stdout);
	scanf("%d%d",&n,&m);
	memset(A,0,sizeof(A));
	for(int i=1;i<=n;i++) 
	    for(int j=1;j<=m;j++)
	    	scanf("%d",&A[i][j]);
	s=0,t=2*n*m+1;
	for(int i=1;i<=n;i++)
	    for(int j=1;j<=m;j++)
	    {
	    	if(A[i][j]==2)
	    	{
	    		if(i%2==1)
	    		{
	    			inser(s,pos1(i,j),1);
	    			if(A[i-1][j]==1&&i-1>=1) inser(pos1(i,j),pos1(i-1,j),1);
	    			if(A[i][j-1]==1&&j-1>=1) inser(pos1(i,j),pos1(i,j-1),1);
	    			if(A[i][j+1]==1&&j+1<=m) inser(pos1(i,j),pos1(i,j+1),1);
	    			if(A[i+1][j]==1&&i+1<=n) inser(pos1(i,j),pos1(i+1,j),1);
	    		}
	    		else 
	    		{
	    			inser(pos1(i,j),t,1);
	    		    if(A[i-1][j]==1&&i-1>=1) inser(pos2(i-1,j),pos1(i,j),1);
	    			if(A[i][j-1]==1&&j-1>=1) inser(pos2(i,j-1),pos1(i,j),1);
	    			if(A[i][j+1]==1&&j+1<=m) inser(pos2(i,j+1),pos1(i,j),1);
	    			if(A[i+1][j]==1&&i+1<=n) inser(pos2(i+1,j),pos1(i,j),1);
	    		}
	    	}
	    	else if(A[i][j]==1) inser(pos1(i,j),pos2(i,j),1);
	    }
	cout<<maxflow(s,t);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值