UVA 818 (dfs+二进制枚举)
题意:给n个点,然后给几个数对,每个数字代表一个圆环,表示这两个环连在一起,然后求需要打开几个环,能够让这n个环形成一个链。
分析:因为n的范围是1~15,所以可以二进制枚举哪个环需要断开,然后在该状态下判断是否满足条件(即当前没有环,并且所有的都没有两个分支),并且判断需要断开的部分是否大于等于原来的链子。
1 #include <stdio.h>
2 #include <string.h>
3 #define min(a,b) (a)<(b)?(a):(b)
4 #define INF 0x3f3f3f3f
5 const int N = 20;
6 int n, g[N][N], vis[N], cn;
7 bool two(int s)
8 {
9 for (int i = 0; i < n; i++)
10 {
11 if (s&(1<<i)) continue;
12 int num = 0;
13 for (int j = 0; j < n; j++)
14 {
15 if (s&(1<<j)) continue;
16 if (g[i][j]) num++;
17 }
18 if (num > 2) return true;
19 }
20 return false;
21 }
22 bool dfs(int s, int now, int fa)
23 {
24 vis[now] = 1;
25 for (int i = 0; i < n; i++)
26 {
27 if (!g[now][i] || (s&(1<<i)) || i == fa) continue;
28 if (vis[i]) return true;
29 if (dfs(s, i, now)) return true;
30 }
31 return false;
32 }
33 bool circle(int s)
34 {
35 for (int i = 0; i < n; i++)
36 {
37 if (vis[i] || (s&(1<<i))) continue;
38 cn++;
39 if (dfs(s, i, -1)) return true;
40 }
41 return false;
42 }
43 int cal(int s)
44 {
45 return s == 0 ? 0 : cal(s / 2) + (s&1);
46 }
47 int solve()
48 {
49 int ans = INF;
50 int s = (1<<n);
51 for (int i = 0; i < s; i++)
52 {
53 cn = 0;
54 memset(vis, 0, sizeof(vis));
55 if(two(i) || circle(i)) continue;///如果有两个分支或者有环就不满足
56 if (cal(i) >= cn - 1)///如果开的部分大于剩下的链数
57 ans = min(cal(i), ans);
58 }
59 return ans;
60 }
61 int main()
62 {
63 int cas = 0;
64 while (~scanf("%d", &n) && n)
65 {
66 int a, b;
67 memset(g, 0, sizeof(g));
68 while (~scanf("%d%d", &a, &b) && a != -1 && b != -1)
69 g[a - 1][b - 1] = g[b - 1][a - 1] = 1;
70 printf("Set %d: Minimum links to open is %d\n", ++cas, solve());
71 }
72 return 0;
73 }
人生就像心电图,想要一帆风顺,除非game-over


浙公网安备 33010602011771号