(1)思路:
可以交换行或列,其实只要只交换行,或者只交换列就可以了,因为整行交换总能达到最终的效果。
所以考虑要交换的行,每次找到第i行中的第k个位置为1,那么只要将这一行与第k行交换就好了。
所以第i行与第k行就建立了一条边。
利用这个关系建立二分图,求出最大匹配。
如果所有的边都可以得到匹配,就说明可以让所有对角线上全部变为1,
然后模拟这个过程,用bj[i]数组表示第i个组的现在的位置是bj[i],
从第一个要交换的开始交换,判断接下来的是否还需要交换,
如果有必要就交换,否则不交换。这样就得到了最终最少的交换次数。
(2)代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<utility>
using namespace std;
const int maxn = 1e4+10;
int head[maxn],vis[105],pre[105],nxt[105],n,tot,bj[maxn];
struct Node{
int v,nxt;
}cur[maxn<<2];
void Init(){
memset(head,-1,sizeof(head));
tot = 0;
}
void Add(int x,int y){
cur[tot].v = y;
cur[tot].nxt = head[x];
head[x] = tot++;
}
bool dfs(int x){
for(int i=head[x];i!=-1;i=cur[i].nxt){
int y = cur[i].v;
if(vis[y]==0){
vis[y] = 1;
if(pre[y]==-1||dfs(pre[y])){
pre[y] = x;nxt[x] = y;
return true;
}
}
}
return false;
}
int fun(){
memset(pre,-1,sizeof(pre));
memset(nxt,-1,sizeof(nxt));
int ans = 0;
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++;
}
return ans;
}
void SP(int &x,int &y){
int tp = x;x = y;y = tp;
}
int main(void){
while(~scanf("%d",&n)){
Init();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
int x;scanf("%d",&x);
if(x!=0) Add(i,j);
}
int ans = fun();
if(ans!=n){
printf("-1\n");
continue;
}
vector <pair <int,int> > vc;
for(int i=1;i<=n;i++) bj[i] = i;//表示第i行有存储着原来的第bj[i]行.
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)
if(bj[j]==i){ //找到要交换的第j行
if(j!=nxt[i]){ //如果还没有交换
vc.push_back(make_pair(j,nxt[i]));
SP(bj[j],bj[nxt[i]]); //交换第j行与第nxt[i]行。
}
break;
}
}
int len = vc.size();
printf("%d\n",len);
for(int i=0;i<len;i++){
printf("R %d %d\n",vc[i].first,vc[i].second);
}
}
return 0;
}