其他分享
首页 > 其他分享> > 【二分图】文理分班

【二分图】文理分班

作者:互联网

【二分图】文理分班

标签(空格分隔): 图论 二分图


【前提级】

此文理分班非彼文理分班,如果找的是bzoj的那道文理分班可以绕道了

【题目】

题目描述

jzyz每年的文理分班的时候,每个班都会有一些同学分到其他班,还会进入一些其他班的同学进入这个班。

小x负责安排座位,为了照顾分班带来的那种伤感情绪,小x制定了很人性化的座位安排计划,具体计划如下:

比如A和B都是本班学生且是好朋友,A分到了其他班,而C则是外班进入这个班的,C和A并不熟悉,而C和B关系很好,那么小x为了照顾A和C的情绪,就会让B坐在A的位置,C坐在B的位置。

当然,实际情况可能很复杂,比如一个班里的同学之间关系不一定好,外班进来的可能和本班很多人关系都很好。

现在告诉你,和小x所在班有关系的人一共有n个人,小x想知道有没有一个合理的方案来满足自己的座位安排计划。

输入格式

本题为多组数据,第一行一个整数M,表示有M组测试数据。

对于每组测试数据,每组的第一行一个整数n,表示一共有n个人和这个班有关系。

接下来一行n个整数,第i个整数表示第i个人是否是本班学生(0表示不是,1表示是,分到其他班的也算是本班学生)

接下来一行n个整数,第i个整数表示第i个人是否要分到其他班(0表示留在本班,1表示分到其他班,如果第i个人是由外班分进来的,那么第i个整数就是一个随机整数,没有实际意义)

接下来是一个n行n列的一个二维矩阵,第i行第j列的数表示第i个人和第j个人是否关系很好(1表示认识,0表示不认识),对角线上是0,但是自己肯定认识自己。

输出格式

每组数据,如果存在一个方案,输出 “_”(不含引号)。

如果没有方案,输出 “T_T”(不含引号)。都是半角字符。

输入输出样例

输入 #1
1
3
1 1 0
0 1 0
0 1 1
1 0 0
1 0 0
输出 #1
_

【思路】

这题是二分图中第一道需要自己判断谁左谁右的题,拿到时很懵,搜了下题解发现只有一篇,然而只有代码,没有思路,就很气,结果自己发现有个地方还是不理解,如果有错误请指出,希望来个兄弟能有个说法。
左右子图表示可以换座,我们需要建立一个这样的图,跑一遍匈牙利,但是建图的过程比较难以理解。
直接看代码中的注释吧,有点难表述。

【代码】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=1e3+500,INF=0x3f3f3f3f;
int n,m,t,vis[maxn],girls[maxn],a[maxn],b[maxn],p[maxn][maxn];
vector<int> g[maxn];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')w=-1;ch=getchar();
	}
	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
bool Find(int u){
	for(int i=0;i<g[u].size();i++){
		int v=g[u][i];
		if(!vis[v]){
			vis[v]=1;
			if(girls[v]==0||Find(girls[v])){
				girls[v]=u;
				return 1;
			}
		}
	}
	return 0;
	
}//板子不会建议回炉
int main(){
	freopen("a.in","r",stdin);
	t=read();
	while(t--){
		for(int i=0;i<maxn;i++)g[i].clear();
		n=read();
		for(int i=1;i<=n;i++)a[i]=read();
		for(int i=1;i<=n;i++){
			b[i]=read();
			if(b[i]!=0&&b[i]!=1)b[i]=0;//肯定是隔壁班的人需要分进来的
			if(a[i]==1&&b[i]==0)g[i].push_back(i);//如果自己在本班且自己不被分出去,肯定可以和自己换座(可能有些人爆零在这里)
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				int x=read();
			//	if(a[j]==0)x=0;
				if(x==1&&a[j]==1){//i和j是好朋友,且j是本班的,i就可以换j
					g[i].push_back(j);//i能换j不代表j换i,因为i可能不在本班又不分进本班,此时j就不可能换i
				}
			}
		}
		bool flag=0;
		memset(girls,0,sizeof(girls));
		for(int i=1;i<=n;i++){
			memset(vis,0,sizeof(vis));
			if(!a[i]||(a[i]&&!b[i])){//先解释判断后面,如果i在本班,且不被分出去,肯定会被换座。判断前面i不在本班的情况我一开始不是很懂,但是题目中说所有人都与本班有关系,所以i不在本班肯定会需要分进本班,所以需要查找
				if(!Find(i)){
					cout<<"T_T"<<endl;
					flag=1;
					break;
				}
			}
		}
		if(flag==0)cout<<"^_^"<<endl;
	}
	
}

题外话

可能有的地方理解不对,望指出

标签:二分,ch,本班,文理,maxn,include,分班
来源: https://www.cnblogs.com/614685877--aakennes/p/12841088.html