洛谷 P2055 [ZJOI2009]假期的宿舍 二分图 匈牙利算法 链式前向星 与自己上一篇思路的异同

题目链接:

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

这种思路来源博客:

https://www.luogu.com.cn/blog/cjyyb/solution-p2055

自己关于本题的上一篇博客:

https://blog.csdn.net/aiwo1376301646/article/details/104240204

算法:1:匈牙利算法

1:异:主要区别是我上一篇的思路是让汉子节点的可能取值在1到n之间,妹子可能取值是在n+1到2*n之间,相当于把n个同学左右两边各写一份,更加好看出是一个二分图,我处理的时候只让确定的汉子节点(不是本校或者是本校且不回家)和确定的妹子节点(本校学生)连线,而直接忽略是本校但是回家的学生,因为他不是汉子节点

2:同:这个博客是节点范围就是1到n,把所有的关系(边)只要边的终点可以提供床位(是本校学生)(是妹子)都连上了,其实你画图模拟的时候其实发现结果是一样的(这个好像自己又有点不清楚啦)

3:特别注意这个矩形图是关于主对角线对称的,并且主对角线全是0

#include<bits/stdc++.h>

using namespace std;
const int maxn=5e1+1,maxl=maxn*maxn;

struct Line
{
    int v,next;
}e[maxl];

int cnt,tot,t,n,a,sum,home[maxn],school[maxn],h[maxn],match[maxn];
bool vis[maxn];

inline void add(int u,int v)
{
       e[cnt]=(Line){v,h[u]};
       h[u]=cnt++;
}

bool dfs(int x)
{
       for(int i=h[x];i!=-1;i=e[i].next)
       {
              int v=e[i].v;
              if(!vis[v])
              {
                    vis[v]=true;
                    if(!match[v]||dfs(match[v]))
                    {
                            match[v]=x;
                            return true;
                    }
              }
       }
       return false;
}

int main()
{
       ios::sync_with_stdio(0);
       cin>>t;
       while(t--)
       {
             cnt=tot=0;
             memset(h,-1,sizeof(h));
             cin>>n;
             for(int i=1;i<=n;++i)
                cin>>school[i];
             for(int i=1;i<=n;++i)
             {
                  cin>>home[i];
                  if(home[i]==0&&school[i])//如果此人是在校学生并且不回家
                     add(i,i);//可以睡自己的床
             }
             for(int i=1;i<=n;++i)//统计要床的人
               if(!school[i]||(school[i]&&!home[i]))++tot;
             for(int i=1;i<=n;++i)
             {
                  for(int j=1;j<=n;++j)
                  {
                         cin>>a;
                         if(a&&school[j])//如果i认识j并且j是学生
                               add(i,j);//i可以睡j的床
                  }
             }
             memset(match,0,sizeof(match));
             sum=0;
             for(int i=1;i<=n;++i)
             {
                   if((school[i]&&home[i]==0)||!school[i])//要么是学生在学校,要么是外来的人
                   {
                         memset(vis,0,sizeof(vis));
                         if(dfs(i))++sum;
                   }
             }
             if(sum==tot)cout<<"^_^"<<endl;
             else cout<<"T_T"<<endl;
       }
       return 0;
}
发布了117 篇原创文章 · 获赞 37 · 访问量 6559

猜你喜欢

转载自blog.csdn.net/aiwo1376301646/article/details/104240878