Description
Given an N*N matrix with each entry equal to 0 or 1. You can swap any two rows or any two columns. Can you find a way to make all the diagonal entries equal to 1?
Input
There are several test cases in the input. The first line of each test case is an integer N (1 <= N <= 100). Then N lines follow, each contains N numbers (0 or 1), separating by space, indicating the N*N matrix.
Output
For each test case, the first line contain the number of swaps M. Then M lines follow, whose format is “R a b” or “C a b”, indicating swapping the row a and row b, or swapping the column a and column b. (1 <= a, b <= N). Any correct answer will be accepted, but M should be more than 1000.
If it is impossible to make all the diagonal entries equal to 1, output only one one containing “-1”.
If it is impossible to make all the diagonal entries equal to 1, output only one one containing “-1”.
题意:给出一个0/1矩阵,问是否可以通过不断交换两行或两列得到一个左上右下对角线全是1的矩阵。如果可以,输出任意方案。(R a b交换a,b两行,C a b交换a,b两列)。有special judge,要求步骤数小于1000。
这题我一开始根本不觉得这和二分图有什么关系。。这几天搜索题做多了,第一反应是构造h函数。。然而这题确实巧妙。你可以先假定有一个主对角线全是1其他全是0的矩阵,然后乱交换几次看看,就有规律了:无论交换哪两行或者两列,得到的都是一个置换矩阵(每行每列仅一个1)。那么问题就显然是求原矩阵中是否包含一个置换矩阵。由于每行每列仅一个一,就将原图中所有行作为X部,列作为Y部,对矩阵中每个1将其行和列连边,检查是否满流即可。
至于输出方案,将那个置换矩阵取出来,再模拟一次给所有1的y坐标升序排序的过程即可。为了让交换次数尽量少,建议手写选择排序。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 250
#define MAXM 51000
int N, M, cnt;
int mat[MAXN][MAXN];
struct Node { int to; Node*next; };
struct BiGraph {
int match[MAXN], xn;
bool vis[MAXN];
Node Edge[MAXM*2], *ecnt, *adj[MAXN];
BiGraph() { memset(adj,0,sizeof adj); ecnt=Edge; }
void addedge(int a, int b)
{
++ecnt;
ecnt->to = b;
ecnt->next = adj[a];
adj[a] = ecnt;
}
bool dfs(int u)
{
for (Node*p = adj[u]; p; p=p->next) {
int &v = p->to;
if (vis[v]) continue;
vis[v] = 1;
if (!match[v] || dfs(match[v])) {
match[u] = v; match[v] = u;
return 1;
}
}
return 0;
}
int Maxmatch()
{
int ans = 0;
for (int i = 1; i<=xn; ++i)
if (!match[i]) {
memset(vis, 0, sizeof vis);
ans += dfs(i);
}
return ans;
}
} Empty, G;
int a[MAXN];
int x1[1000], x2[1000];
int main()
{
int i, j;
while (~scanf("%d", &N)) {
G = Empty;
G.xn = N;
M = cnt = 0;
for (i = 1; i<=N; ++i)
for (j = 1; j<=N; ++j) {
scanf("%d", &mat[i][j]);
if (mat[i][j])
G.addedge(i, j+N);
}
if (G.Maxmatch() < N) {
puts("-1");
continue;
}
for (i = 1; i<=N; ++i)
for (j = 1; j<=N; ++j)
if (mat[i][j] && G.match[i]==j+N)
a[++cnt] = j;
for (i = 1; i<=N; ++i) {
if (a[i] == i) continue;
for (j = i; j<=N; ++j)
if (a[j] == i) {
swap(a[i], a[j]);
++M;
x1[M] = i; x2[M] = j;
break;
}
}
printf("%d\n", M);
for (i = 1; i<=M; ++i)
printf("R %d %d\n", x1[i], x2[i]);
}
return 0;
}