[CODEVS1222] 信与信封问题
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
题目描述 Description
John先生晚上写了n封信,并相应地写了n个信封将信装好,准备寄出。但是,第二天John的儿子Small John将这n封信都拿出了信封。不幸的是,Small John无法将拿出的信正确地装回信封中了。
将Small John所提供的n封信依次编号为1,2,…,n;且n个信封也依次编号为1,2,…,n。假定Small John能提供一组信息:第i封信肯定不是装在信封j中。请编程帮助Small John,尽可能多地将信正确地装回信封。
输入描述 Input Description
n文件的第一行是一个整数n(n≤100)。信和信封依次编号为1,2,…,n。
n接下来的各行中每行有2个数i和j,表示第i封信肯定不是装在第j个信封中。文件最后一行是2个0,表示结束。
输出描述 Output Description
输出文件的各行中每行有2个数i和j,表示第i封信肯定是装在第j个信封中。请按信的编号i从小到大顺序输出。若不能确定正确装入信封的任何信件,则输出“none”。
样例输入 Sample Input
3
1 2
1 3
2 1
0 0
样例输出 Sample Output
1 1
提交地址:CODEVS1222
题解:
我们先跑一遍匈牙利,找出最大匹配, 如果匹配数量和n不同的话, 直接输出none;
然后我们对于每一条连着的边, 如果它是必须的,那么去掉它之后一定不能形成完美匹配;
然后每条边都去一遍,不行就输出;
Code:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int n; 7 bool del[110][110]; 8 bool vis[110]; 9 int line[110], lik[110]; 10 int ans; 11 12 inline bool dfs(int x) 13 { 14 for (register int i = 1 ; i <= n ; i ++) 15 { 16 if (vis[i] or del[x][i]) continue; 17 vis[i] = 1; 18 if (!line[i] or dfs(line[i])) 19 { 20 line[i] = x; 21 lik[x] = i; 22 return 1; 23 } 24 } 25 return 0; 26 } 27 28 int main() 29 { 30 cin >> n; 31 int a, b; 32 while (scanf("%d%d", &a, &b) != EOF) 33 { 34 if (a == 0 and b == 0) break; 35 del[a][b] = 1; 36 } 37 for (register int i = 1 ; i <= n ; i ++) 38 { 39 memset(vis, 0, sizeof vis); 40 ans += dfs(i); 41 } 42 if (ans != n) {puts("none");return 0;} 43 bool fl = 0; 44 for (register int i = 1 ; i <= n ; i ++) 45 { 46 int t = lik[i]; 47 del[i][t] = 1; 48 lik[i] = 0, line[t] = 0; 49 memset(vis, 0, sizeof vis); 50 if (!dfs(i)) 51 { 52 printf("%d %d\n", i, t); 53 line[t] = i, lik[i] = t; 54 fl = 1; 55 } 56 del[i][t] = 0; 57 } 58 if (!fl) {puts("none");return 0;}; 59 return 0; 60 }