BZOJ1059: [ZJOI2007]矩阵游戏

发现了史上最大的BUG ……

Yes打上了YES  调的欲哭无泪&%#*&@!……

不胡扯了 下面是题解

首先我们会发现    同一行用一列上的 黑色格子无论怎样换行 总是在同一行同一列上

那么我们可以把每一行  每一列作为状态 进行二分图匹配

若F[i][j]=1 则表示 第i行 和 第j列 可以匹配  然后直接 匈牙利就行了


形象的说 就是 可以把每一行看做一个士兵  每一列看做一个阵营

每一个士兵都可以到达许多阵营(许多列) 但只能占有一个阵营(一列) 

然后就看最多能占有多少阵营就行了  如果等于n 那么有解,否则无解

2333…………(被Shymuel大神嘲讽了好久手速慢,语文没学好各种被骂…………)

蒟蒻就只能描述这些了…………

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
using namespace std;
int head[222],d[42222][2],state[222],from[222];
int n,t,cnt,TI;
void insert(int a,int b)
{
	d[++cnt][0]=b; d[cnt][1]=head[a]; head[a]=cnt;
}
int hungary(int x)
{
	for(int i=head[x]; i; i=d[i][1])
	 if(state[d[i][0]]!=TI)
	 {
	 	  state[d[i][0]]=TI;//时间戳
	 	  if(!from[d[i][0]] || hungary(from[d[i][0]]) )
	 	  {
	 	  	  from[d[i][0]]=x;
	 	  	  return 1;
	 	  }
	 }
	return 0;
}
int main()
{
	scanf("%d",&t);
	while( t-- )
	{
		cnt=0;
		memset(head,0,sizeof(head));
		memset(from,0,sizeof(from));
		scanf("%d",&n);
		for(int i=1; i<=n; i++) 
		  for(int j=1; j<=n; j++)
		  {
		  	  int x; scanf("%d",&x);
		  	  if(x) insert(i,j);
		  }
		bool flag=0;
		for(int i=1; i<=n; i++)
		{
			TI++;//用一个时间戳可以加速一下匈牙利,拒绝memset
			if(!hungary(i)) {flag=1; break; }
		}
		if(flag) printf("No\n");
		else printf("Yes\n");
	}
	return 0;
}


你可能感兴趣的:(二分图匹配)