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; }