题目链接:
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;
}