链接http://www.lydsy.com/JudgeOnline/problem.php?id=1059
构造一个二分图,其中行对应的编号是0到n-1,列对应的编号是n到2n-1,若矩阵中的元素m[i][j]为1则,在顶点i和n+j之间连一条边。求这个图的最大匹配。如果最大匹配数等于n,说明,矩阵经过一系列操作可以变成这样的:存在n个1,任意两个1不在同一行或者同一列。之后通过构造法:对刚才提到的n个1,进行按行操作,若某行中1在第一列,就把该行与第一行交换,此后不再动这行,其余n-1行按照上述操作依次进行,即可得到题目要求的矩阵:主对角线上的元素均为1.
参考代码:
/**************************************************************
Problem: 1059
User: sfailsthy
Language: C++
Result: Accepted
Time:348 ms
Memory:1696 kb
****************************************************************/
//BZOJ自动生成这个,很人性化。。。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int maxn =400+10;
int V;
vector<int> G[maxn];
int match[maxn];
bool used[maxn];
void add_edge(int u,int v){
G[u].push_back(v);
G[v].push_back(u);
}
bool dfs(int v){
used[v]=true;
for(int i=0;i<G[v].size();i++){
int u=G[v][i],w=match[u];
if(w<0||!used[w]&&dfs(w)){
match[v]=u;
match[u]=v;
return true;
}
}
return false;
}
int bitpartite_matching(){
int res=0;
memset(match,-1,sizeof(match));
for(int v=0;v<V;v++){
if(match[v]<0){
memset(used,0,sizeof(used));
if(dfs(v)){
res++;
}
}
}
return res;
}
int main(){
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
V=2*n;
for(int i=0;i<V;i++){
G[i].clear();
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
int x;
scanf("%d",&x);
if(x){
add_edge(i,j+n);
}
}
}
int res=bitpartite_matching();
if(res==n){
printf("Yes\n");
}
else{
printf("No\n");
}
}
return 0;
}