1. 程式人生 > >【杭電100題】RPG專場練習賽 2063 過山車(匈牙利演算法)

【杭電100題】RPG專場練習賽 2063 過山車(匈牙利演算法)

Problem Description

過山車的每一排只有兩個座位,每個女生必須找個男生做partner和她同坐,每個女生都願意跟若干男生做partner。只讓找到partner的人去坐過山車,最多有多少對組合可以坐上過山車?

Input

輸入資料的第一行是三個整數K , M , N,分別表示可能的組合數目,女生的人數,男生的人數。0<K<=1000 1<=N 和M<=500.接下來的K行,每行有兩個數,分別表示女生Ai願意和男生Bj做partner。最後一個0結束輸入。

Output

對於每組資料,輸出一個整數,表示可以坐上過山車的最多組合數。

 【2018/11/7】

因為一開始關於visit陣列我沒看懂,所以在這裡再補充幾句:

演算法思路是:讓每一個女生獨自尋找男生,如果找到了,那麼組合數+1

尋找過程的程式碼如下:

//女生x來尋找partner
bool find(int x)
{
    //遍歷每一個男生i
    for(int i=0; i<n; i++)
    {
        //若女生x未找過男生i
        //且女生x願意和男生i做partner
        if(!visit[i]&&map[x][i])
        {
            //記錄男生i被找過
            visit[i]=1;

            //如果男生i還沒有partner
            //或者男生i的匹配女生能夠再找到新的匹配男生
            if(partner[i]==-1||find(partner[i]))
            {
                //那麼就讓女生x和男生i匹配
                partner[i]=x;

                //返回女生x找到了partner
                return true;
            }
        }
    }
    //女生x無法找到partner
    return false;
}

尋找的過程是:

女生x尋找每一個自己心儀的男生i,

當男生i沒有被找過,即visit[i]==0,且女生x願意找男生i,即map[x][i]=1,

當滿足上述兩個條件時,記錄男生i被找過了,接下來女生x問男生i:你已經和別的女生匹配了嗎?

①如果partner[i]==-1,證明男生i還沒有匹配,此時可以讓partner[i]=x,讓女生x和男生i匹配,返回true,

②如果男生i已經有匹配了,匹配的女生為第partner[i]號,但是這個女生可以再找到別的男生跟她匹配,也就是find(partner[i])返回了true,此時也可以讓partner[i]=x,讓女生x和男生i匹配,返回true,

如果女生x找遍了每一個男生i,都沒人能跟她匹配,返回false,證明沒有找到。

visit[]陣列的意義在於:

在上述的第②種情況中,我們需要讓女生partner[i]去尋找【除了男生i之外的別的男生】跟她匹配,

在find(partner[i])中,visit[i]已經等於1,不滿足尋找條件,女生partner[i]就不會再找男生i了。

由此可見,visit陣列的作用是在女生x尋找時,有可能需要遞迴呼叫find函式,以讓別的女生重新匹配,這時記錄找過的男生可以在重新匹配的過程中排除被找過的男生,

所以!!在遍歷每一個女生x,讓女生x去尋找之前,都要清空visit陣列,因為這個時候女生x還沒開始找,每一個男生都還沒被找過。

 完整程式碼如下:

(杭電oj給的男女生編號從1開始,我的陣列從0開始,因此對輸入資料做了-1處理)

#include <iostream>

using namespace std;

int k;
int m;  //女生數目
int n;  //男生數目
int output; //組合數
int map[501][501];      //記錄某女生是否願意與某男生做partner
int partner[501];       //記錄某男生的partner是某女生
int visit[501];         //記錄某男生是否被找過

void init();
bool find(int x);

int main()
{
    int girl,boy;
    while(cin>>k&&k)
    {
        //輸入資料
        cin>>m>>n;

        //陣列初始化
        init();

        //輸入資料
        for(int i=0; i<k; i++)
        {
            cin>>girl>>boy;
            map[girl-1][boy-1]=1;
        }

        //陣列初始化
        init();

        //讓每一個女生去尋找partner
        for(int i=0; i<m; i++)
        {
            //此時任何男生都沒被找過
            for(int j=0; j<n; j++)
            {
                visit[j]=0;
            }
            //如果該女生找到partner,那麼組合數+1
            if(find(i))
            {
                output++;
            }
        }

        //輸出資料
        cout<<output<<endl;
    }
    return 0;
}

//初始化函式
void init()
{
    for(int i=0; i<m; i++)
    {
        for(int j=0; j<n; j++)
        {
            map[i][j]=0;
        }
    }
    //此時每個男生沒有partner
    for(int i=0; i<n; i++)
    {
        partner[i]=-1;
    }
    //組合數為0
    output=0;
}

//女生x來尋找partner
bool find(int x)
{
    //遍歷每一個男生i
    for(int i=0; i<n; i++)
    {
        //若女生x未找過男生i
        //且女生x願意和男生i做partner
        if(!visit[i]&&map[x][i])
        {
            //記錄男生i被找過
            visit[i]=1;

            //如果男生i還沒有partner
            //或者男生i的匹配女生能夠再找到新的匹配男生
            if(partner[i]==-1||find(partner[i]))
            {
                //那麼就讓女生x和男生i匹配
                partner[i]=x;

                //返回女生x找到了partner
                return true;
            }
        }
    }
    //女生x無法找到partner
    return false;
}

【2018/11/7後記】

1、僅僅在半年之前,我的杭電100題刷題之旅差不多也就卡在這個地方

現在想起來還是心生感慨、感恩這半年的不懈努力和進步(雖然暑假都被荒廢了但這學期很努力啊)

既然因為機緣巧合,時隔半年又做到這道題,那麼差不多也要從這裡開始,繼續將沒刷的題刷完

2、偷偷在這裡立個flag,要在放假之前把杭電100題刷完,把所有原始碼整理上傳,然後假期繼續leetcode(雖然只會做簡單題orz)

寫在這裡應該不會有人看到吧^^,完不成也不丟臉hhhh