bzoj1059[ZJOI2007] 矩阵游戏

题目链接:bzoj1059

题目大意:

给一个N*N的矩阵,上面有黑白两种颜色的格子。每次可以对该矩阵进行两种操作:行交换操作:选择矩阵的任意两行,交换这两行(即交换对应格子的颜色)列交换操作:选择矩阵的任意行列,交换这两列(即交换对应格子的颜色)游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。问有没有方案能实现。


题解:

二分图最大匹配

因为由题意(%hyc)可以发现,实际上是求有没有n个行列互不相同的棋子。于是把行跟列当二分图连边(有点像网络流的经典模型),x行y列有个黑棋子就连x->y。跑个二分图最大匹配就好了。
然而我一直在往求最大点独立集那方面想..而时间复杂度也根本不允许我建图...

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 41000

struct node
{
	int x,y,next;
}a[maxn*2];int len,first[maxn];
int n,bf[maxn],ask[maxn],tim;
void ins(int x,int y)
{
	++len;
	a[len].x=x;a[len].y=y;
	a[len].next=first[x];first[x]=len;
}
int ffind(int x)
{
	for (int i=first[x];i!=-1;i=a[i].next)
	 if (ask[a[i].y]!=tim)
	 {
		 int y=a[i].y;
		 ask[y]=tim;
		 if (bf[y]==-1 || ffind(bf[y]))
		 {
			 bf[y]=x;
			 return true;
		 }
	 }
	return false;
}
bool xyl()
{
	memset(ask,0,sizeof(ask));
	memset(bf,-1,sizeof(bf));
	for (int i=1;i<=n;i++)
	{
		tim++;
		if (!ffind(i)) return false;
	}
	return true;
}
int main()
{
	int T,i,j,x;
	scanf("%d",&T);
	while (T--)
	{
		len=tim=0;
		memset(first,-1,sizeof(first));
		scanf("%d",&n);
		for (i=1;i<=n;i++)
	  	 for (j=1;j<=n;j++)
		 {
			scanf("%d",&x);
			if (x==1) ins(i,j);
		 }
		if (xyl()) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}


posted @ 2017-02-25 08:16  OxQ  阅读(125)  评论(0编辑  收藏  举报