UVa 818 切断圆环链(dfs+二进制枚举)

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 }
时间: 2024-08-07 00:13:03

UVa 818 切断圆环链(dfs+二进制枚举)的相关文章

【UVA】11464-Even Parity(二进制枚举子集)

枚举第一行的所有可能情况,之后根据上面行计算下面行(判断是否冲突),获得最终结果. 14058243 11464 Even Parity Accepted C++ 0.275 2014-08-18 05:14:15 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> #include<stack> #inc

UVA 818 Cutting Chains (DFS)

What a find! Anna Locke has just bought several links of chain some of which may be connected. They are made from zorkium, a material that was frequently used to manufacture jewelry in the last century, but is not used for that purpose anymore. It ha

poj3279(dfs+二进制枚举思路)

题意转载自https://www.cnblogs.com/blumia/p/poj3279.html 题目属性:DFS 相关题目:poj3276 题目原文:[desc]Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which they manipulate an

UVa818 Cutting Chains (二进制枚举)

链接:http://vjudge.net/problem/35523 分析:links记录初始圆环链的情况,然后二进制枚举编号为0~n-1的圆环哪个被打开了,一个圆环最多一个前驱和一个后继,所以judge判断如果有一个未打开的圆环同时和2个以上的未打开圆环相连就一定不能形成链,剪去.circle判断剩下的未打开圆环是否形成环,以及若未成环那么有多少条单链links_num,注意最后成链不用按顺序比如1->2->3...这样.然后判断一下打开的圆环数够不够把links_num条单链扣成一条链,若

Uva LA6450 Social Advertising DFS

You have decided to start up a new social networking company. Other existing popular social networksalready have billions of users, so the only way to compete with them is to include novel features noother networks have.Your company has decided to ma

CUGBACM_Summer_Tranning1 二进制枚举+模拟+离散化

整体感觉:这个组队赛收获还挺多的.自从期末考试以后已经有一个多月没有 做过组队赛了吧,可是这暑假第一次组队赛就找回了曾经的感觉.还挺不错的!继续努力!! 改进的地方:这次组队赛開始的时候题目比較难读懂,然后就感觉题目应该比較难吧,认为应该是区域赛难度的题目.尽管A题和B题自己都感觉能自己A的.可是可能对自己不太自信,所以让队友大帝敲了.要是当时自己敢敲一下的话,后续会更快的A掉吧. A题:二进制枚举 题目链接:https://icpcarchive.ecs.baylor.edu/external

uva 12253 - Simple Encryption(dfs)

题目链接:uva 12253 - Simple Encryption 题目大意:给定K1,求一个12位的K2,使得KK21=K2%1012 解题思路:按位枚举,不且借用用快速幂取模判断结果. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const ll ite=(1<<20)-1; ll N; /* l

UVa1151&amp;POJ2784--Buy or Build【kruskal+二进制枚举】

链接: UVa http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3592 POJ http://poj.org/problem?id=2784 题意:告诉你n个点的坐标,建立一颗最小生成树,不过有q个套餐,套餐是连通某些点,并有一定花费,求最小生成树. 思路:n个点,n最大为1000,则最多有1000*999/2条边,先不使用套餐求一遍最小生

51nod 1363 最小公倍数的和 欧拉函数+二进制枚举

1363 最小公倍数之和 题目来源: SPOJ 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 给出一个n,求1-n这n个数,同n的最小公倍数的和.例如:n = 6,1,2,3,4,5,6 同6的最小公倍数分别为6,6,6,12,30,6,加在一起 = 66. 由于结果很大,输出Mod 1000000007的结果. Input 第1行:一个数T,表示后面用作输入测试的数的数量.(1 <= T <= 50000) 第2 - T + 1行:T个数A[i](A[i] <