1. 程式人生 > >杭電OJ2063 (基礎二分圖匹配)(月老降臨)

杭電OJ2063 (基礎二分圖匹配)(月老降臨)

過山車

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 15700    Accepted Submission(s): 6886


Problem Description RPG girls今天和大家一起去遊樂場玩,終於可以坐上夢寐以求的過山車了。可是,過山車的每一排只有兩個座位,而且還有條不成文的規矩,就是每個女生必須找個個男生做partner和她同坐。但是,每個女孩都有各自的想法,舉個例子把,Rabbit只願意和XHD或PQK做partner,Grass只願意和linle或LL做partner,PrincessSnow願意和水域浪子或偽酷兒做partner。考慮到經費問題,boss劉決定只讓找到partner的人去坐過山車,其他的人,嘿嘿,就站在下面看著吧。聰明的Acmer,你可以幫忙算算最多有多少對組合可以坐上過山車嗎?
Input 輸入資料的第一行是三個整數K , M , N,分別表示可能的組合數目,女生的人數,男生的人數。0<K<=1000
1<=N 和M<=500.接下來的K行,每行有兩個數,分別表示女生Ai願意和男生Bj做partner。最後一個0結束輸入。
Output 對於每組資料,輸出一個整數,表示可以坐上過山車的最多組合數。
Sample Input 6 3 3 1 1 1 2 1 3 2 1 2 3 3 1 0
Sample Output 3

這是一道非常非常經典的二分圖匹配的題目.

這個二分匹配的題也可以理解為你是一位月老,一點一點的,通過尋找增廣路來湊成一對又一對.

最大二分匹配的思路核心很簡單:

無腦列舉,尋找最優解.

不斷的通過列舉尋找增廣路~

比如這個題目的思路就靠兩個for迴圈構成題目的核心:
第一個for:

        int output=0;//當然是輸出的結果啦~
        for(int i=1;i<=n;i++)//這裡n表示男生的人數.(男生一般臉皮都比較厚所以要男生主動去問女生啦~(其實都可以)).
        {
            memset(vis,0,sizeof(vis));
            if(find(i))//派每一個男生去找他喜歡的女孩紙~~~~~~~~~如果找到了能夠同意他的女孩紙~~~~就算是籌上了一對~~~~~~
            output++;
        }
然後是第二個for
int  find(int x)
{
    for(int i=1;i<=m;i++)//有這麼m個小姑娘小夥子需要去詢問(一旦找到了能和自己湊成一對的小姑娘就停.)
    {
        if(vis[i]==0&&map[i][x])//如果當前小姑娘沒有詢問過(你要是詢問兩次人家小姑娘嫌你煩你造吧~~~~).並且這個小姑娘能同意了的情況下.
        {
            vis[i]=1;
            if(pri[i]==-1||find(pri[i]))//如果這個小姑娘沒有其他男生曾過來和她約,或者是她約了其他小夥子但是還能讓她約了的這個小夥子找到其他小姑娘.
            {
                pri[i]=x;//這個小夥子就算是和這個小姑娘搭上愛之橋了(誰知道會不會有後來人把這個小夥子趕跑.....)(可憐的一群屌絲.....)
                return 1;
            }
        }
    }
    return 0;
}


這樣子我們就歡歡喜喜的讓最多組的男生和女生約在一起咯~~~~~~~



然後

這裡貼上AC程式碼;

#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn = 505;

int map[maxn][maxn];              //圖的陣列.
int vis[maxn];                  //標記陣列.
int pri[maxn];
int k,m,n;
int  find(int x)
{
    for(int i=1;i<=m;i++)
    {
        if(vis[i]==0&&map[i][x])
        {
            vis[i]=1;
            if(pri[i]==-1||find(pri[i]))
            {
                pri[i]=x;
                return 1;
            }
        }
    }
    return 0;
}
int main()
{
    while(~scanf("%d",&k))
    {
        if(k==0)break;
        scanf ("%d%d", &m, &n);
        memset (map, 0, sizeof (map));
        memset (pri, -1, sizeof (pri));
        for(int i=0;i<k;i++)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            map[a][b]=1;
        }
        int output=0;
        for(int i=1;i<=n;i++)
        {
            memset(vis,0,sizeof(vis));
            if(find(i))
            output++;
        }
        printf("%d\n",output);
    }
}