1. 程式人生 > >【網路流】【二分圖多重匹配】【Hungary演算法】HDU 3605 Escape

【網路流】【二分圖多重匹配】【Hungary演算法】HDU 3605 Escape

【大意】有n個人和m個星球,每個人有想去的星球,星球有最大容納量,問能否給所有的人都安排上?

【思路】本來是最大流的題..但是n太大了,會T,看部落格說要用狀壓...就學了一波匈牙利演算法求二分圖最大匹配...狀壓的寫法有空補一補...

                         就是讓每一個男的直接匹配他清單上第一個女的,如果第一個被人匹配了,就去讓那個男的找他的下一個女的,如果找到了,新來的男的就和這個女的匹配,否則這個男的就找下一個女的。

【二分圖多重匹配】多重匹配就是女的可以找好幾個老公,有上限。就把上面的改成:如果這個女的男票數量沒有達到上上限,就直接匹配,否則嘗試擠掉每一個她的男友,成功就匹配,失敗就找下一個女的。

【匈牙利演算法的程式碼】

//虛擬碼
bool dfs(int u)//尋找從u出發的增廣路徑
{
    for each v∈u的鄰接點
        if(v未訪問){
            標記v已訪問;
            if(v未匹配||dfs(cy[v])){
                cx[u]=v;
                cy[v]=u; 
                return true;//有從u出發的增廣路徑
            }
        }
    return false;//無法找到從u出發的增廣路徑
}
//程式碼
bool dfs(int u){
    for(int v=1;v<=m;v++)
        if(t[u][v]&&!vis[v]){
            vis[v]=1;
            if(cy[v]==-1||dfs(cy[v])){
                cx[u]=v;cy[v]=u;
                return 1;
            }
        }
    return 0;
}
void maxmatch()//匈牙利演算法主函式
{
    int ans=0;
    memset(cx,0xff,sizeof cx);
    memset(cy,0xff,sizeof cy);
    for(int i=0;i<=nx;i++) 
        if(cx[i]==-1)//如果i未匹配
        { 
            memset(visit,false,sizeof(visit)) ; 
            ans += dfs(i); 
        }
    return ans ;
} 

【程式碼】

#include<cstdio>
#include<cstring>

const int Mn=100005;
const int Mm=15;
int mp[Mn][Mm];
int volume[Mm];//每個星球的容量
int n,m;
int ymatch[Mm][Mn];//ymatch[哪個星球][星上第幾個人]=是誰
int cnt[Mn];//cnt[哪個星球]=已經住了多少人
bool vis[Mm];

bool dfs(int x)///僅僅是找x有沒有能娶的
{
    for(int i=0; i<m; i++)
    {
        if(vis[i])
            continue;
        if(mp[x][i]==0)
            continue;
        vis[i]=1;
        if(cnt[i]<volume[i])//如果還能加人
        {
            ymatch[i][cnt[i]]=x;
            cnt[i]++;
            return 1;
        }
        else
        {
            for(int j=0; j<cnt[i]; j++)
            {
                if(dfs(ymatch[i][j]))
                //如果本來配完的這個人還能去別的地方
                {
                    ymatch[i][j]=x;
                    return 1;
                }
            }
        }
    }
    return 0;
}


void hungary()
{
    for(int i=0; i<n; i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i)==0)
        {
            printf("NO\n");//只要有一個人不能匹配就no
            return;
        }
    }
    printf("YES\n");
    return;
}

int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        memset(cnt,0,sizeof(cnt));
        memset(mp,0,sizeof(mp));
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                int t;
                scanf("%d",&t);
                mp[i][j]=t;
            }
        }
        for(int i=0; i<m; i++)
            scanf("%d",&volume[i]);
        hungary();
    }

}