HNU 11979 Roll call 二分图匹配
时间:2014-04-29 11:47:46
收藏:0
阅读:335
题意:
众所周知,老师经常在班级上点名。点名是从名单上叫一个人的名字或者id来判断名单上这个人是否在场。学生们总是有各种各样的理由不来,所以他们需要其他人帮他们答到。但是打到工作不是这么简单,出于各种考虑,他们答道遵循以下原则。
1. 每个来上课的人必须给自己达到;
2. 每个来上课的人,只能帮另外一个人达到;
3. 如果一个人想帮助另外一个人答道,那么他们id的差至少大于等于K。
现在老师又要点名了,请问是否存在一种情况,使老师相信每个人都到场了。
输入:
第一行有一个整数T,表示接下来会有T组数据。
对于每组数据,第一行包含三个整数N, M, K (1<=N<=10^9,2<=M,K<=150),告诉你一共有N个学生,有M个学生到场了,K是id的最小差。第二行有M个整数,表示到场学生的id。
思路:
二分图匹配
代码: 用的增广路算法,还没学MK
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int MAXN = 400; 8 9 bool vis[MAXN]; 10 bool present[MAXN]; 11 int id[MAXN]; 12 int matched[MAXN]; 13 int N, M, K; 14 15 inline int myAbs(int x) { 16 return x>0 ? x : -x; 17 } 18 19 bool dfs(int v) { 20 vis[v] = true; 21 for (int u = 1; u <= N; u++) if ((present[u]^present[v]) && (myAbs(u-v)>=K)) { 22 int w = matched[u]; 23 if (w<0 || (!vis[w] && dfs(w))) { 24 matched[v] = u; 25 matched[u] = v; 26 return true; 27 } 28 } 29 return false; 30 } 31 32 int Match() { 33 int res = 0; 34 memset(matched, -1, sizeof(matched)); 35 for (int v = 1; v <= N; v++) { 36 if (matched[v]<0) { 37 memset(vis, false, sizeof(vis)); 38 if (dfs(v)) { 39 res++; 40 } 41 } 42 } 43 return res; 44 } 45 46 int main() { 47 #ifdef Phantom01 48 freopen("HNU11979.txt", "r", stdin); 49 #endif // Phantom01 50 51 int T; 52 scanf("%d", &T); 53 54 while (T--) { 55 scanf("%d%d%d", &N, &M, &K); 56 for (int i = 0; i < M; i++) { 57 scanf("%d", &id[i]); 58 } 59 if (N>(M<<1)) { 60 puts("N"); 61 continue; 62 } 63 memset(present, false, sizeof(present)); 64 for (int i = 0; i < M; i++) 65 present[id[i]] = true; 66 if ((N-M)==Match()) puts("Y"); 67 else puts("N"); 68 } 69 70 return 0; 71 }
评论(0)