【网络流】【二分图多重匹配】【Hungary算法】HDU 3605 Escape

【题目】http://acm.hdu.edu.cn/showproblem.php?pid=3605

【大意】有n个人和m个星球,每个人有想去的星球,星球有最大容纳量,问能否给所有的人都安排上?

【思路】本来是最大流的题..但是n太大了,会T,看博客说要用状压...就学了一波匈牙利算法求二分图最大匹配...状压的写法有空补一补...

【参考】http://www.cppblog.com/JulyRina/archive/2015/02/13/209816.html(反了)

               https://www.cnblogs.com/nanke/archive/2012/04/15/2450185.html

【二分图匹配】匈牙利算法https://blog.csdn.net/c20180630/article/details/70175814

                         就是让每一个男的直接匹配他清单上第一个女的,如果第一个被人匹配了,就去让那个男的找他的下一个女的,如果找到了,新来的男的就和这个女的匹配,否则这个男的就找下一个女的。

【二分图多重匹配】多重匹配就是女的可以找好几个老公,有上限。就把上面的改成:如果这个女的男票数量没有达到上上限,就直接匹配,否则尝试挤掉每一个她的男友,成功就匹配,失败就找下一个女的。

【匈牙利算法的代码】

//伪代码
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();
    }

}

猜你喜欢

转载自blog.csdn.net/qq_32259423/article/details/81363054
今日推荐