洛谷 P2055 [ZJOI2009]假期的宿舍 二分图 匈牙利算法 汉子找妹子模型

题目链接:

https://www.luogu.com.cn/problem/P2055

算法:1匈牙利算法

思路

1:一道经典的汉子找妹子模型,关键是找对谁是汉子,谁是妹子

2:需要床的是汉子,可以提供床的是妹子

3:那么即不是本学校的学生和是本学校的学生但是不回家的人需要床是汉子,所有的本校学生都可以提供床,都是妹子

4:那么就是汉子节点连妹子妹子节点构成二分图

一:使用读入优化

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e2+1;
int t,n,a,tot,now,head[maxn],to[maxn*maxn],next[maxn*maxn],match[maxn],vis[maxn],student[maxn][2];

inline void clear()//初始化
{
// for(int i=1;i<=tot;i++)to[i]=next[i]=head[i]=0;
    tot=0;
    for(int i=n+1;i<=2*n;i++)match[i]=vis[i]=0;
    for(int i=1;i<=n;i++)student[i][0]=student[i][1]=to[i]=next[i]=head[i]=0;
}

inline int read()//读入优化
{
    int s=0,w=1;
    char g=getchar();
    while(g<'0'||g>'9')
    {
        if(g=='-')w*=-1;
        g=getchar();
    }
    while(g>='0'&&g<='9')
    {
        s=s*10+g-'0';
        g=getchar();
    }
    return s*w;
}

inline void add(int x,int y)//链式前向星
{
    tot++;
    to[tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}

bool dfs(int x)//匈牙利算法
{
    for(int i=head[x],y;i;i=next[i])
    {
        if(vis[y=to[i]]==now)continue;
        vis[y]=now;
        if(!match[y]||dfs(match[y]))
        {
            match[y]=x;
            return true;
        }
    }
    return false;
}

int main()
{
    ios::sync_with_stdio(0);
    t=read();
    while(t--)
    {
        n=read();
        for(int i=1;i<=n;i++)scanf("%d",&student[i][0]);//存是否是本校学生
        for(int i=1;i<=n;i++)scanf("%d",&student[i][1]);//存是否回家
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
        {
            a=read();
            if(student[i][0]&&!student[i][1])//二分图的左边是汉子:是本校学生,并且不回家
            {
                if(student[j][0])//右边是本校同学,可以提供床,是妹子,编号为n+1到2*n
                {
                    if(a==1||i==j)add(i,j+n);//则建边
                }
            }
            else if(!student[i][0])//二分图的左边是汉子:不是本校学生
            {
                if(student[j][0])//右边是本校同学,可以提供床,是妹子,编号为n+1到2*n
                {
                    if(a==1)add(i,j+n);//则建边
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            if((student[i][0]&&!student[i][1])||!student[i][0])//如果是汉子节点,则给他找妹子
            {
                now=i;
                if(!dfs(i))//如果某一个汉子找不到妹子
                {
                       printf("T_T\n");
                       break;
                }
            }
            if(i==n)printf("^_^\n");
        }
        clear();
    }
    return 0;
}

二:不使用读入优化

#include <bits/stdc++.h>

using namespace std;
const int maxn=1e2+1;
int t,n,a,tot,now,head[maxn],to[maxn*maxn],next[maxn*maxn],match[maxn],vis[maxn],student[maxn][2];

inline void clear()
{
    tot=0;
    for(int i=n+1;i<=2*n;i++)match[i]=vis[i]=0;
    for(int i=1;i<=n;i++)student[i][0]=student[i][1]=to[i]=next[i]=head[i]=0;
}

inline void add(int x,int y)
{
    tot++;
    to[tot]=y;
    next[tot]=head[x];
    head[x]=tot;
}

bool dfs(int x)
{
    for(int i=head[x],y;i;i=next[i])
    {
        if(vis[y=to[i]]==now)continue;
        vis[y]=now;
        if(!match[y]||dfs(match[y]))
        {
            match[y]=x;
            return true;
        }
    }
    return false;
}

int main()
{
    ios::sync_with_stdio(0);
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)scanf("%d",&student[i][0]);
        for(int i=1;i<=n;i++)scanf("%d",&student[i][1]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
        {
            scanf("%d",&a);
            if(student[i][0]&&!student[i][1])
            {
                if(student[j][0])
                {
                    if(a==1||i==j)add(i,j+n);
                }
            }
            else if(!student[i][0])
            {
                if(student[j][0])
                {
                    if(a==1)add(i,j+n);
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            if((student[i][0]&&!student[i][1])||!student[i][0])
            {
                now=i;
                if(!dfs(i))
                {
                       printf("T_T\n");
                       break;
                }
            }
            if(i==n)printf("^_^\n");
        }
        clear();
    }
    return 0;
}
发布了117 篇原创文章 · 获赞 37 · 访问量 6561

猜你喜欢

转载自blog.csdn.net/aiwo1376301646/article/details/104240204
今日推荐