[ZJOI2009]假期的宿舍
洛谷题目链接:假期的宿舍
题目描述
学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题。比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识。我们假设每个人只能睡和自己直接认识的人的床。那么一个解决方案就是 B 睡 A 的床而 C 睡 B 的床。而实际情况可能非常复杂,有的人可能认识好多在校学生,在校学生之间也不一定都互相认识。我们已知一共有 n 个人,并且知道其中每个人是不是本校学生,也知道每个本校学生是否回家。问是否存在一个方案使得所有不回家的本校学生和来看他们的其他人都有地方住。
输入输出格式
输入格式:
第一行一个数 T 表示数据组数。接下来 T 组数据,每组数据第一行一个数n 表示涉及到的总人数。接下来一行 n 个数,第 i 个数表示第 i 个人是否是在校学生 (0 表示不是,1 表示是)。再接下来一行 n 个数,第 i 个数表示第 i 个人是否回家 (0 表示不回家,1 表示回家,注意如果第 i 个人不是在校学生,那么这个位置上的数是一个随机的数,你应该在读入以后忽略它)。接下来 n 行每行 n 个数,第 i 行第 j 个数表示 i 和 j 是否认识 (1 表示认识,0 表示不认识,第 i 行 i 个的值为 0,但是显然自己还是可以睡自己的床),认识的关系是相互的。
输出格式:
对于每组数据,如果存在一个方案则输出 “^_^”(不含引号) 否则输出“T_T”(不含引号)。(注意输出的都是半角字符,即三个符号的 ASCII 码分别为94,84,95)
输入输出样例
说明
对于 30% 的数据满足 1 ≤ n ≤ 12。
对于 100% 的数据满足 1 ≤ n ≤ 50,1 ≤ T ≤ 20。
多组数据!!!
首先来分析一波题目:大概就是给出若干个人,有些人属于学校的学生,有些是不属于学校的人来学校拜访。在这些属于学校的学生中,有些人住校,有些人回家。现在拜访者们来学校了,他们需要床睡。每个属于学校的学生在学校都有一张床。如果存在认识关系,那么一个人就可以睡另一个人的床。另外,住校的学生可以睡自己的床。现在要求出可以有床睡的人数与住校的学生和来拜访的学生人数之和是否相等。
既然一个人与一张床想匹配,那么是不是很容易联想到二分图?于是我们考虑题目要如何建图:
- 首先肯定是要确定每个学生是否属于学校以及的住校情况。
- 将住校的学生和拜访者与源点连一条流量为1的边。
- 将每个属于学校的学生拆成人和床两个点。
- 确定认识关系,将认识的人与对应的床连一条流量为1的边。
- 将所有的床和汇点连一条流量为1的边。
然后跑一遍最大流,就可以求出最多能有多少人有床睡,与住校的学生和拜访者总量相比,如果>=,则有这样的方案使来的人都有床睡。
最后注意一下数组清零。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=400+5; 4 const int inf=2147483647; 5 6 int n, s, t, sum = 0; 7 int cnt = 1 , ans = 0; 8 int last[N]; 9 int leave[N]; 10 int school[N]; 11 int lev[N]; 12 13 struct edge{ 14 int to, next, cap; 15 }e[3000000]; 16 17 void add(int x,int y,int z){ 18 e[++cnt].to = y; 19 e[cnt].cap = z; 20 e[cnt].next = last[x]; 21 last[x] = cnt; 22 } 23 24 bool bfs(){ 25 queue <int> q; 26 memset(lev,-1,sizeof(lev)); 27 lev[s] = 0 , q.push(s); 28 while(!q.empty()){ 29 int x = q.front(); q.pop(); 30 for(int i=last[x];i;i=e[i].next){ 31 int to = e[i].to; 32 if(lev[to] == -1 && e[i].cap) 33 lev[to] = lev[x]+1 , q.push(to); 34 } 35 } 36 return lev[t] != -1; 37 } 38 39 int dfs(int x,int flow){ 40 if(x == t) return flow; 41 int rest = 0; 42 for(int i=last[x];i;i=e[i].next){ 43 int to = e[i].to; 44 if(lev[to] == lev[x]+1 && e[i].cap){ 45 int f = dfs(to,min(flow-rest,e[i].cap)); 46 if(f){ 47 rest += f; 48 e[i].cap -= f; 49 e[i^1].cap += f; 50 } 51 } 52 } 53 return rest; 54 } 55 56 int main(){ 57 //freopen("data.in","r",stdin); 58 int T; cin >> T; 59 while(T--){ 60 memset(last,0,sizeof(last)); 61 sum = ans = 0; cnt = 1; 62 int x; cin >> n; 63 s = 0; t = n*2+1; 64 for(int i=1;i<=n;i++){ 65 cin >> school[i]; 66 if(school[i] == 1) add(i+n,t,1) , add(t,i+n,0); 67 } 68 for(int i=1;i<=n;i++){ 69 cin >> leave[i]; 70 if(school[i] == 0 || (school[i] == 1&&leave[i] == 0)) 71 add(s,i,1) , add(i,s,0) , sum++; 72 } 73 for(int i=1;i<=n;i++) 74 for(int j=1;j<=n;j++){ 75 x = 0; cin >> x; 76 if(x == 1 || i == j) 77 add(i,j+n,1) , add(j+n,i,0); 78 } 79 while(bfs()) ans += dfs(s,inf); 80 //printf("ans=%d sum=%d\n",ans,sum); 81 if(ans >= sum) printf("^_^\n"); 82 else printf("T_T\n"); 83 } 84 return 0; 85 }