传送门点击打开链接
题目大意 :给出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;
}