1. 程式人生 > 其它 >P1129 [ZJOI2007] 矩陣遊戲

P1129 [ZJOI2007] 矩陣遊戲

技術標籤:P1129ZJOI2007矩陣遊戲最大匹配

文章目錄

R e s u l t Result Result

...


H y p e r l i n k Hyperlink Hyperlink

https://www.luogu.com.cn/problem/P1129


D e s c r i p t i o n Description Description

給定一個大小為 n × n n\times n n×n的0/1矩陣,你可以進行若干次操作,每次交換任意兩行或兩列,問是否存在一種方案使得該正方形對角線上全是1

資料範圍: n ≤ 200 n\leq 200 n200


S o l u t i o n Solution Solution

一條對角線上全是一等價於每一行每一列都有一且被聯絡在一起

由於這一聯絡關係,我們可以把行和列看做一個個節點,它們分屬兩個集合,而一個位置為1說明其把行和列聯絡在了一起,若一條對角線上都是1,說明行和列全部匹配完畢,達到了最大匹配

而交換行/列的操作相當於改變邊連線的位置,而這不會影響匹配數

因此,存在方案當且僅當原二分圖最大匹配恰好為 n n n,跑最大匹配即可

時間複雜度: O ( n 3 ) O(n^3) O(n3)(最壞情況)


C o d e Code Code

#include<cstdio>
#include<cstring>
#define N 221
#define M 40121
#define LL long long
#define r(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
struct node{
int next,to;}edge[M];int T,l[N],tot,x,n,link[N],ans;bool vis[N]; void add(int u,int v){edge[++tot].to=v;edge[tot].next=l[u];l[u]=tot;return;} inline LL read() { char c;LL f=0,d=1; while((c=getchar())<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48; while((c=getchar())>=48&&c<=57)f=(f<<3)+(f<<1)+c-48; return d*f; } inline int find(int p) { for(int i=l[p];i;i=edge[i].next) if(!vis[edge[i].to]) { vis[edge[i].to]=1; int q=link[edge[i].to]; link[edge[i].to]=p; if(!q||find(q)) return true; link[edge[i].to]=q; } return false; } int main() { T=read(); while(T--) { memset(l,0,sizeof(l));memset(link,0,sizeof(link));tot=0; n=read(); for(register int i=1;i<=n;i++) for(register int j=1;j<=n;j++) { scanf("%d",&x); if(x) add(i,j); } ans=0; for(register int i=1;i<=n;i++) memset(vis,0,sizeof(vis)),ans+=find(i); puts(ans==n?"Yes":"No"); } }