文理分班[二分图]
题目描述
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
3
1 1 0
0 1 0
0 1 1
1 0 0
1 0 0
样例输出
^_^
思路
首先diss出题人, 把话说清楚能死? 阅读理解也没宁这么出的
"n
个人和这个班有关系。" 在这的意思是, 不是本班的学生一定会分来本班, 因为他和这个班有联系
小x要管的人, 只包括本班教室里的人 (没有被分走的本班学生和分进来的外班学生)
明确了题意,我们来解释一下样例的3,4行
1 1 0
0 1 0
第一个人:是本班学生, 没有分走
第二个人:是本班学生,但被分到了外班
第三个人:不是本班学生, 一定会分来本班, 第二行的 0 只是一个随机整数, 而不是代表他留在自己的班
好了!只要你搞清楚题意, 这道题就是个板子 (出题人我谢谢宁全家)
考虑一下哪些人可以相互换坐
- 自己是本班学生, 没被分走, 自己可以坐在自己的座位上(和自己换坐)
- 某个人和本班的一个学生是朋友, 他们两个就可以换坐(即使本班的这个学生被分走, 他的座位还留在本班教室)
对小x需要管的人跑一边匈牙利, 如果一个人找不到可以换坐的, 就可以直接break了
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1050;
int n, k, m, vis[maxn], match[maxn], ans, g[maxn][maxn], a[maxn], b[maxn];
int find(int u){//匈牙利
for(int i=1; i<=n; i++){
if(g[u][i] && !vis[i]){
vis[i] = 1;
if(!match[i] || find(match[i])){
match[i] = u;
return 1;
}
}
}
return 0;
}
int main(){
scanf("%d", &m);
while(m--){
memset(g, 0, sizeof(g));
memset(match, 0, sizeof(match));//记得初始化
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]);//是否为本班学生
for(int i=1; i<=n; i++){
scanf("%d", &b[i]);//是否分走
if(a[i]==1 && b[i]==0) g[i][i] = 1;//是本班学生且没被分走,自己可以和自己换坐
}
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
int x; scanf("%d", &x);
if(x==1 && a[j]==1) g[i][j] = 1;//i和j很熟, 且j是本班的(即使j被分到外班,j的座位还在本班)
}
}
bool flag = 0;
for(int i=1; i<=n; i++){
memset(vis,0,sizeof(vis));
if((!a[i]) || (a[i]&&!b[i])){//没有被分走的本班学生和分进来的外班学生
if(!find(i)){//找不到可以换坐的人
flag=1;
break;
}
}
}
printf("%s
", flag ? "T_T" : "^_^");
}
return 0;
}