D173 二分图最大匹配 匈牙利算法 P1129 [ZJOI2007] 矩阵游戏
D173 二分图最大匹配 匈牙利算法 P1129 [ZJOI2007] 矩阵游戏_哔哩哔哩_bilibili
有一个 01 方阵,每一次可以交换两行或两列,问是否可以通过交换使得主对角线(左上到右下)全都是 1
思路
观察发现,最终主对角线上的 n 个 1 均不在同一行、同一列,问题转化成能否找到初始时 n 个不在同一行、同一列的 1
对于一个 1
而言,最终方案中选了这个 1
代表这个 1
的行、列被占用
我们可以把行、列坐标拆成左、右两部点, n 个左部点代表行、n 个右部点代表列,这样方阵就转化为二分图
对于方阵中 1
,从它的行的左部点到它的列的右部点连一条有向边,如果选择这条边,代表其行、列被占用
跑二分图最大匹配,只要找到的匹配边 $ans==n$,说明可以找到 n 个行、列均不同的 1,那就有解,否则无解

参考:D25【模板】二分图最大匹配 匈牙利算法 - 董晓 - 博客园
// 二分图 匈牙利算法 O(V*E) #include<bits/stdc++.h> using namespace std; const int N=405; vector<int> e[N]; int T,n,ans; int vis[N],match[N]; //女生参与,配对信息 bool dfs(int u){ for(auto v:e[u]){ if(vis[v]) continue; //若女生v已参与这一轮试配,就跳过 vis[v]=1; if(!match[v] || dfs(match[v])){ //若女生v没配对 或 女生v的男友可以另选她人 match[v]=u; //记录v的男友是u return 1; //返回配对成功 } } return 0; //返回配对失败 } int main(){ cin>>T; while(T--){ scanf("%d",&n); for(int i=1,v;i<=n;i++)for(int j=1;j<=n;j++){ scanf("%d",&v); if(v==1) e[i].push_back(j); } for(int i=1; i<=n; i++){ memset(vis,0,sizeof(vis)); if(dfs(i))ans++; } if(ans==n) printf("Yes\n"); else printf("No\n"); memset(match,0,sizeof(match)); for(int i=0;i<=n;i++)e[i].clear(); ans=0; } }
浙公网安备 33010602011771号