左边的点集是列标号,右边的点集是在初始时为每一行分配的id
构图:对每个左边的定点,枚举右边的定点,如果右边的行在相应列上为1,则连上一条边
然后找一个完备匹配
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
using namespace std;
#define REP(i,s,t) for(int (i)=(s);(i)<=(t);++(i))
typedef long long LL;
const int maxn = 105;
vector<int> g[maxn + 5];
int cx[maxn + 5], cy[maxn+5];
int vis[maxn + 5];
int m[maxn + 5][maxn + 5];
int a[maxn+5];
int pos[maxn+5];
int save[maxn+5][2];
bool match(int x) {
int len = g[x].size();
int node;
for (int i=0;i<len;++i)
if (!vis[g[x][i]]) {
node = g[x][i];
vis[node] = 1;
if (cy[node] == -1 || match(cy[node])) {
cy[node] = x;
cx[x] = node;
return true;
}
}
return false;
}
int main() {
int n;
while (cin >> n) {
REP(i, 0, n-1)
REP(j, 0, n-1)
scanf("%d",&m[i][j]);
REP(i, 0, n-1)
g[i].clear();
REP(i, 0, n-1)
REP(j, 0, n-1)
if (m[j][i])
g[i].push_back(j);
memset(cx, -1, sizeof(cx));
memset(cy, -1, sizeof(cy));
REP(i, 0, n-1) {
if (cx[i] == -1) {
memset(vis, 0, sizeof(vis));
match(i);
}
}
bool ok = true;
REP(i, 0, n-1)
if (cx[i] == -1) {
ok = false;
break;
}
if (!ok) {
cout << -1 << endl;
} else {
REP(i, 0, n-1) {a[i] = i;pos[i] = i;}
int ans_cnt = 0;
REP(i, 0, n-1) {
if (cx[i] != a[i]) {
save[ans_cnt][0] = i+1;save[ans_cnt++][1] = pos[cx[i]]+1;
int tmp = a[i];
a[i] = cx[i];
a[pos[cx[i]]] = tmp;
pos[tmp] = pos[cx[i]];
pos[cx[i]] = i;
}
}
cout << ans_cnt << endl;
REP(i, 0, ans_cnt-1)
printf("R %d %d\n", save[i][0], save[i][1]);
}
}
return 0;
}