文理分班[二分图]

文理分班[二分图]

题目描述

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

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

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

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

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

输入格式

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

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

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

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

接下来是一个nn列的一个二维矩阵,第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 只是一个随机整数, 而不是代表他留在自己的班

好了!只要你搞清楚题意, 这道题就是个板子 (出题人我谢谢宁全家)

考虑一下哪些人可以相互换坐

  1. 自己是本班学生, 没被分走, 自己可以坐在自己的座位上(和自己换坐)
  2. 某个人和本班的一个学生是朋友, 他们两个就可以换坐(即使本班的这个学生被分走, 他的座位还留在本班教室)

对小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\n", flag ? "T_T" : "^_^");
    }
    return 0;
}
posted @ 2020-05-12 21:34  poozhai  阅读(236)  评论(1编辑  收藏  举报