題目大意:給定一個矩陣,矩陣元素取值爲0或1,每次操作可以交換任意兩行或兩列,要求對於給定矩陣給出操作次數和操作序列將主對角線(A[i][i],i=1...n)元素全部變爲1,無法滿足則輸出-1.
題意分析:首先要意識到如果有解,一定可以全部由行交換或者列交換來完成。不妨以行交換爲例,行交換不改變元素的列次序,也就是說,若想A[2][2]爲1,必須A[i][2](i=1..n)中有一個或者多個1.那麼,如果問題有解,就變成找出一個序列,使得某一個行來滿足某一列的對角線值唯一(有點繞口)。或者說,每一次調整一行的位置使得某一列上的對角線元素爲1.
進一步抽象,就變成了,把指定的行號分配給指定的列號,如果每個列號都能分配到,那麼就有解。就是二分圖的最大匹配。匹配數量如果小於n,則無解。
有解時,由於具體匹配情況已經求出,問題就變成給定一個1..N的序列,求出一系列的交換使得序列恢復1,2,3,...,N-1,N的順序。記錄交換次數,然後輸出交換次序即可。(具體做法:如果元素s[i]!=i,那麼找到s[j]==i將這兩個元素交換即可,雙重循環)
最後一個問題:是R還是C?我提交的時候寫了R,但是wa了,改成C好了。仔細想想,在第一步時,行與列沒有區別,行匹配列與列匹配行都一樣。這個問題卡了我一下午。仔細思考這個道題:a[i][j]=1到底代表什麼?代表:
1.第i行放到第j行可以使得第j行的主對角線爲1;
2.第j列放到第i列可以使得第j列的主對角線爲1;
也就是說,這道題目中,圖是有向的,看你怎麼解釋。那麼,只要確定匈牙利算法得到的匹配次序究竟是什麼就可以解釋了。
下面一個例子:
4
0 1 0 0
0 0 1 0
0 0 0 1
1 0 1 1
答案:
3 3
C 1 2 R 1 4
C 2 3 R 2 4
C 3 4 R 3 4
match數組:
match [0] [1] [2] [3]
[3] [0] [1] [2]
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 505;
const int Mod = 1000000007;
const double inf = 1<<30;
int n,m;
int map[maxn][maxn];
int cx[maxn],cy[maxn];
bool vis[maxn];
struct Node
{
int x,y;
}node[maxn];
void Swap( int &a,int &b )
{
int tmp = a;
a = b;
b = tmp;
}
bool FindPath( int u )
{
for( int i = 1; i <= n; i ++ )
{
if( !vis[i] && map[u][i] )
{
vis[i] = true;
if( cy[i] == -1 || FindPath( cy[i] ) )
{
cy[i] = u;
cx[u] = i;
return true;
}
}
}
return false;
}
int MaxMatch()
{
int ans = 0;
memset( cx,-1,sizeof(cx) );
memset( cy,-1,sizeof(cy) );
for( int i = 1; i <= n; i++ )
{
if( cx[i] == -1 )
{
memset( vis,0,sizeof(vis) );
ans += FindPath( i );
}
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("data.txt","r",stdin);
#endif
int a,b;
while( scanf("%d",&n) != EOF )
{
memset( map,0,sizeof(map) );
for( int i = 1; i <= n; i ++ ){
for( int j = 1; j <= n; j ++ )
scanf("%d",&map[i][j]);
}
if( MaxMatch() < n )
puts("-1");
else
{
m = 0;
for( int i = 1; i <= n; i ++ )
{
if( cx[i] != i )
{
for( int j = i+1; j <= n; j ++ ){
if( cx[j] == i ){
node[m].x = i;
node[m++].y = j;
Swap( cx[i],cx[j] );
break;
}
}
}
}
printf("%d\n",m);
for( int i = 0; i < m; i ++ )
printf("R %d %d\n",node[i].x,node[i].y);
}
}
return 0;
}