题目链接: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;
}