https://vjudge.net/problem/UVA-818
题意:有n个圆环,其中有一些已经扣在了一起。现在需要打开尽量少的圆环,使得所有圆环可以组成一条链,例如,有5个圆环,1-2,2-3,4-5,则需要打开一个圆环,如圆环4,然 后用它穿过圆环3和圆环5后再次闭合4,就可以形成一条链:1-2-3-4-5。
思路:从n个圆环中任意选择圆环,这就是枚举子集。所以这道题目可以用二进制枚举来做。
那么如何判断当前打开圆环是可行的呢?在去除打开的圆环后需要判断:
①:每个圆环的分支数都必须小于等于2,大于2个肯定就不能成为单链了。
②:不能存在环。
③:连通分支数-1不能大于打开圆环数。
判断是否存在圆环和连通分支数都可以用dfs来实现。
1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n,cnt,number; 7 int map[20][20]; 8 int vis[20]; 9 int ans; 10 11 bool two(int s) //判断是否有分支数大于2的圆环 12 { 13 for (int i = 0; i < n; i++) 14 { 15 int cnt = 0; //记录分支数 16 for (int j = 0; j < n; j++) 17 { 18 //如果圆环i和j连通并且没有打开i或j时,i圆环的分支数+1 19 if (map[i][j] && !(s&(1 << i)) && !(s & 1 << j)) 20 { 21 cnt++; 22 if (cnt == 3) return true; 23 } 24 } 25 } 26 return false; 27 } 28 29 bool dfs(int x,int f,int s) //判断是否有回路存在 30 { 31 vis[x]=1; 32 for (int i = 0; i < n; i++) 33 { 34 if (map[x][i]) 35 { 36 if (i == f || (s&(1 << i))) continue; //如果i是上一次访问的圆环或者i圆环被打开,进行下一次判定 37 if (vis[i]) return true; //存在回路 38 if (dfs(i, x, s)) return true; 39 } 40 } 41 return false; 42 } 43 44 bool circle(int s) 45 { 46 memset(vis, 0, sizeof(vis)); 47 for (int i = 0; i < n; i++) 48 { 49 if (!vis[i] && !(s & (1 << i))) 50 { 51 number++; //连通分量数+1 52 if (dfs(i , -1, s)) return true; 53 } 54 } 55 return false; 56 } 57 58 int calc(int s) //计算出打开圆环的个数 59 { 60 int cnt = 0; 61 for (int j = 0; j < n; j++) 62 { 63 if (s&(1 << j)) cnt++; 64 } 65 return cnt; 66 } 67 68 void solve() 69 { 70 ans = 100000; 71 for (int i = 0; i < (1 << n); i++) //二进制枚举打开圆环的情况 72 { 73 number = 0; 74 if (two(i) || circle(i)) continue; //如果不行,进行下一次判断,如果不存在两个分支或回路,则正好计算出了连通分支数 75 int count = calc(i); 76 if (number - 1 <= count) ans = min(ans, count); //连通分支数-1不能多于打开的圆环数 77 } 78 } 79 80 int main() 81 { 82 //freopen("D:\txt.txt", "r", stdin); 83 int a, b, kase=0; 84 while (cin >> n && n) 85 { 86 memset(map, 0, sizeof(map)); 87 while (cin >> a >> b && a != -1 && b != -1) 88 { 89 map[a-1][b-1] = 1; 90 map[b-1][a-1] = 1; 91 } 92 solve(); 93 cout<<"Set "<<++kase<<": Minimum links to open is "<<ans<<endl; 94 } 95 return 0; 96 }