问题描述
给定一个N*N矩阵,每个元素都等于0或1。您可以交换任意两行或任意两列。你能找到一种方法使所有对角元素都等于1吗?
输入
输入中有几个测试用例。每个测试用例的第一行是一个整数N (1 <= N <= 100)。然后是N行,每一行包含N个数字(0或1),按空间分开,表示N*N矩阵。
输出
对于每个测试用例,第一行包含的数量M,然后M行,其格式是“R a b”或“C a b”,表明交换行a和行b,或交换列a和列b。(1 < = a、b < = N)。任何正确的答案将被接受,但应该超过1000。
如果不可能使所有对角元素都等于1,那么只输出一个包含“-1”的元素。
分析:
先求最大匹配,如果最大匹配不等于n说明不可能满足条件(类似‘摆放象棋的车’那题)。
我以为匹配就用在判断上,接下来的交换我真的是一行一行换的。。
就是从第一个开始,如果对角线上的不等于1,向下搜索,搜到交换完能变成1的就一整行交换。
但是这样无限wa,(后来想了想知道是为什么了)
正解是利用匹配结果,不仅能保证交换次数而且肯定正确。
看别人代码学到的(不好解释,直接看代码思考)。
这题加深了我对匹配的理解,当场记录!
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=105;
int g[maxm][maxm];
int mark[maxm];
int now[maxm];
int n;
int dfs(int x){
for(int i=1;i<=n;i++){
if(g[x][i]&&!mark[i]){
mark[i]=1;
if(!now[i]||dfs(now[i])){
now[i]=x;
return 1;
}
}
}
return 0;
}
int main(){
while(cin>>n){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>g[i][j];
}
}
int ans=0;
memset(now,0,sizeof now);
for(int i=1;i<=n;i++){
memset(mark,0,sizeof mark);
ans+=dfs(i);
}
if(ans!=n){
cout<<-1<<endl;
continue;
}
vector<int>aa;
vector<int>bb;
for(int i=1;i<=n;i++){
if(now[i]!=i){
for(int j=i+1;j<=n;j++){
if(now[j]==i){
aa.push_back(i);//注意这里交换的是列,所以是C a b
bb.push_back(j);//
swap(now[i],now[j]);
break;
}
}
}
}
printf("%d\n",aa.size());
for(int i=0;i<(int)aa.size();i++){
printf("C %d %d\n",aa[i],bb[i]);
}
}
return 0;
}