2012-12-31 20:19:26Morris

[ZJ][KM算法] d210. 老問題

內容 :

這是個困擾人類數萬年的問題:如何使每個人找到最適合的伴侶?好的對象人人追求,因此追求失敗的比例永遠超過成功率。許多人被迫選擇心目中較差的對象,也產生了大量不美滿的婚姻。

姑且假定地球上的男女一樣多,每個配對都有一個”美滿度”,例如甲男配乙女美滿度為 90 ,丙男配丁女美滿度為40,如此可以得到一個矩陣:

      A男  B男  C男  D男
A女  90   80   80   80
B女  80   20   10   10
C女  85   70   20   10
D女  80   60   80   10

在亞當斯密資本主義理論風行全球的二十世紀中,約翰納許提出了劃時代的創見。也因此獲得了諾貝爾經濟學獎。

他 理論的一個推斷為:倘若所有人同時追求最好的對象,整體婚姻的美滿度反而會下降。舉例而言:假定這個世界是由男性來追求女性,而女性決定他的伴侶,在上面 那個矩陣裡,所有人都想跟A女在一起,A女選擇了在一起後會最美滿的A男,B女則挑了剩下來最好的B男,C配C,D配D,最後四對新人的總美滿度為 90+20+20+10=140。

做點讓步反而會有更好的結果:假定不要每個人都競爭A女,A男配B女;B男配C女;C男配D女;D男配A女,則總美滿度為80+80+70+80=310。

然而在自由競爭的結婚”市場”下,每個個體無法去判斷自己該做怎麼樣的讓步以及該讓到什麼地步,因此你會發現所有人還是努力去追求自己心目中最理想的對象(你會因為跟你朋友討論對面那三個異性怎麼”分配”比較好嗎?)這或許也是離婚率不斷高升的原因之一。

到了二O五O年,政府決定要出面改善這個狀況,等數的男女資料被輸入資料庫,由電腦判斷每種配對的”美滿度”,之後透過程式運算得到最大的總「美滿度」,並根據結果替每位適婚男女安排結婚對象。
你的工作就是依照「美滿度」表找出最佳的配對方式。

當然,每個人最多只能有一個伴侶,但要注意,有些人天生”顧人怨”,沒有人願意跟他/她配對,意即美滿度可以是負數,而不配對的美滿度就是0,簡而言之,如果配對起來美滿度是負數的話不如不配。身為一個程式設計師,你是否能成為稱職的「月下老人」呢?

輸入說明 :

輸入檔包含了多筆的測試資料。

每筆資料第一行為一個正整數N(1≦N≦100),接下來包含N個整數,並以一個空白鍵分隔,其中第i行的第j個整數表示女士Wi與男士Mj配對後的美滿度(可能為負整數或0)。最後一筆資料後會有一行0表示結束。

輸出說明 :

針對每筆資料輸出一個整數,即最大的總美滿度,並以換行分隔。

範例輸入 :help

3
1 2 3
1 2 3
1 2 3
4
90 80 80 80
80 20 10 10
85 70 20 10
80 60 80 10
4
-1 -1 -1 -1
-1 -1 -1 -1
-1 -1 -1 -1
-1 -1 -1 -1
0

範例輸出 :

6
310
0

提示 :

出處 :

NPSC 2005 (管理:magrady)


< 0 的部分當作 0

#include <stdio.h>
#include <string.h>
int W[105][105], N;
int mx[105], my[105]; // match arr
int lx[105], ly[105]; // label arr
int x[105], y[105]; // used arr
int hungary(int nd) {
    int i;
    x[nd] = 1;
    for(i = 1; i <= N; i++) {
        if(y[i] == 0 && W[nd][i] == lx[nd]+ly[i]) {
            y[i] = 1;
            if(my[i] == 0 || hungary(my[i])) {
                my[i] = nd;
                return 1;
            }
        }
    }
    return 0;
}
int KM() {
    int i, j, k, d;
    memset(mx, 0, sizeof(mx));
    memset(my, 0, sizeof(my));
    memset(lx, 0, sizeof(lx));
    memset(ly, 0, sizeof(ly));
    for(i = 1; i <= N; i++)
        for(j = 1; j <= N; j++)
            lx[i] = lx[i] > W[i][j] ? lx[i] : W[i][j];
    for(i = 1; i <= N; i++) {
        while(1) {
            memset(x, 0, sizeof(x));
            memset(y, 0, sizeof(y));
            if(hungary(i))  break;
            d = 0xfffffff;
            for(j = 1; j <= N; j++) {
                if(x[j]) {
                    for(k = 1; k <= N; k++)
                        if(!y[k])
                        d = d < lx[j]+ly[k]-W[j][k] ?
                            d : lx[j]+ly[k]-W[j][k];
                }
            }
            if(d == 0xfffffff)  break;
            for(j = 1; j <= N; j++) {
                if(x[j])    lx[j] -= d;
                if(y[j])    ly[j] += d;
            }
        }
    }
    int res = 0;
    for(i = 1; i <= N; i++) {
        if(my[i])
            res += W[my[i]][i];
    }
    return res < 0 ? 0 : res;
}
int main() {
    int n;
    while(scanf("%d", &n) == 1 && n) {
        N = n;
        int i, j;
        for(i = 1; i <= n; i++) {
            for(j = 1; j <= n; j++) {
                scanf("%d", &W[i][j]);
                if(W[i][j] < 0)
                    W[i][j] = 0;
            }
        }
        printf("%d\n", KM());
    }
    return 0;
}