【杭電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