HDU 2819 Swap (最大二分匹配+輸出路徑)

題目大意就是給出一個矩陣,每個格子裏面要麼是0, 要麼是1;是否能夠經過交換(交換行或者列)使得主對角線上都是1。

其實就行和列的匹配,左邊是行,右邊是列,然後如果行列交點是1,那麼就可以匹配,看是否爲完美匹配,然後輸出怎麼交換的。開始很蒙的,後來仔細去想,可以這樣理解,想要對角線上都是1,那麼我們就可以鎖定行,來選擇列和它匹配,將選擇的列移動到和該行形成對角線上是1的位置,比如和第一行匹配的列,就要移動要第一列,第二行的,就到第二列。其實就是對第i行,找一個第i個數是1的列和它匹配,然後看是否是最大匹配!

至於要輸出路徑,那麼就應該想到是排序的時候交換路徑,也就是說將cy裏面的值,也就是列對應的行,從小到大排序,這個過程中交換的次數和交換的列,就是要輸出的。這裏要求交換次數不能超過1000,使用選擇排序,交換次數最多是N!

那麼存不存在只交換列不能解決,而行列交換一起進行就能解決的情況呢?也就是說我們要證明這個的正確性。其實如果交換行的話,無非是把‘1’的位置放到對角線上,使得某一行和某一列匹配,那麼反過來也可以說是這一列和這一行匹配,其實是一樣的。

做完這道題,我的感悟就是,只是一定要靈活運用,要會思考,不進算法要理解準確,同時應用,以及分析問題同樣十分重要

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 110;
int n, g[N][N], cx[N], cy[N], ans1[N*2], ans2[N*2];
bool used[N];

bool dfs( int u ) 
{
    for ( int i = 1; i <= n; ++i ) if ( g[u][i] && !used[i] ) {
        used[i] = true;
        if ( cy[i] == -1 || dfs( cy[i] ) ) {
            cy[i] = u;
            cx[u] = i;
            return true;
        }
    }
    return false;
}
int match()
{
    int res = 0;
    memset(cx, -1, sizeof(cx));
    memset(cy, -1, sizeof(cy));
    for ( int i = 1; i <= n; ++i ){
        memset( used, 0, sizeof(used));
        if ( dfs(i) ) res++;
        else break;
    }
    return res;
}
int main()
{
    while ( scanf("%d", &n) != EOF ) {
        for ( int i = 1; i <= n; ++i )
            for ( int j = 1; j <= n; ++j ) scanf("%d", &g[i][j]);
        if ( match() != n ) {
            printf("-1\n");
            continue;
        }
        int len = 0;
        for ( int i = 1; i <= n; ++i ) {
            int mark = i, tmp;
            for ( int j = i; j <= n; ++j ) 
                if ( cy[mark] > cy[j] ) mark = j;
            if ( mark == i ) continue;
            ans1[++len] = i, ans2[len] = mark;
            tmp = cy[mark];
            cy[mark] = cy[i];
            cy[i] = tmp;
        }
        printf("%d\n", len);
        for ( int i = 1; i <= len; ++i ) printf("C %d %d\n", ans1[i], ans2[i]);
    }
}
        


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章