D173 二分图最大匹配 匈牙利算法 P1129 [ZJOI2007] 矩阵游戏

D173 二分图最大匹配 匈牙利算法 P1129 [ZJOI2007] 矩阵游戏_哔哩哔哩_bilibili

 

P1129 [ZJOI2007] 矩阵游戏 - 洛谷

有一个 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;
  }
}

 

posted @ 2026-05-26 17:37  董晓  阅读(14)  评论(0)    收藏  举报