UVa818 Cutting Chains (二进制枚举)

链接:http://vjudge.net/problem/35523

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

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5
 6 const int maxn = 20;
 7
 8 int n, links_num, ans, links[maxn][maxn], vis[maxn];
 9
10 void init() {
11     ans = 0x3f3f3f3f;
12     memset(links, 0, sizeof(links));
13     int u, v;
14     while (scanf("%d%d", &u, &v) == 2 && u != -1) {
15         links[u - 1][v - 1] = 1;
16         links[v - 1][u - 1] = 1;
17     }
18 }
19
20 bool judge(int s) {
21     for (int i = 0; i < n; i++) {
22         if (s & (1 << i)) continue;
23         int cnt = 0;
24         for (int j = 0; j < n; j++) {
25             if (s & (1 << j)) continue;
26             if (links[i][j]) cnt++;
27         }
28         if (cnt > 2) return true;
29     }
30     return false;
31 }
32
33 bool dfs(int now, int fa, int s) {
34     vis[now] = 1;
35     for (int i = 0; i < n; i++) {
36         if (!links[now][i] || (s & (1 << i)) || i == fa) continue;
37         if (vis[i]) return true;
38         if (dfs(i, now, s)) return true;
39     }
40     return false;
41 }
42
43 bool circle(int s) {
44     for (int i = 0; i < n; i++) {
45         if (vis[i] || (s & (1 << i))) continue;
46         links_num++;
47         if (dfs(i, -1, s)) return true;
48     }
49     return false;
50 }
51
52 int cal(int s) {
53     return s == 0 ? 0 : cal(s / 2) + (s & 1);
54 }
55
56 void solve() {
57     for (int i = 0; i < (1 << n); i++) {
58         links_num = 0;  memset(vis, 0, sizeof(vis));
59         if (judge(i) || circle(i)) continue;
60         if (cal(i) >= links_num - 1) ans = min(ans, cal(i));
61     }
62 }
63
64 int main() {
65     int kase = 0;
66     while (scanf("%d", &n) == 1 && n) {
67         init();
68         solve();
69         printf("Set %d: Minimum links to open is %d\n", ++kase, ans);
70     }
71     return 0;
72 }
时间: 2024-12-01 06:12:33

UVa818 Cutting Chains (二进制枚举)的相关文章

UVA-818 Cutting Chains (位压缩+暴力搜索)

题目大意:一种环能打开和闭合.现在有n(1<=n<=15)个编号为1~n的环错综复杂的连接着,要打开一些环重新连接使这n个环能构成一条链,问最少需要打开几次环可达到目的? 题目分析:用二进制数表示要打开的环的集合,总共2^n种情形,枚举每一种情况.当把将要打开的环打开后,此环是孤立的,接下来就要判断剩下的环还与几个环连着,如果有的环仍然与两个以上的环连着则该方案不可行,不可能构成链:然后判断剩下的环有没有连成一个圈,如果有,则该方案不可行:最后,判断完前两个条件之后,所有的环都一定处于某条短链

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个圆环中任意选择圆环,这就是枚举子集.所以这道题目可以用二进制枚举来做. 那么如何判断当前打开圆环是可行的呢?在去除打开的圆环后需要判断: ①:每个圆环的分支数都必

POJ 2436 二进制枚举+位运算

题意:给出n头牛的得病的种类情况,一共有m种病,要求找出最多有K种病的牛的数目: 思路:二进制枚举(得病处为1,否则为0,比如得了2 1两种病,代号就是011(十进制就是3)),首先枚举出1的个数等于k的二进制数,然后跟所有的牛的代号一一比较,符合的           +1,找出其中和最大的:就是转换2进制麻烦,用位运算就好实现了,但是位运算不是很明白含义,明白了再补充: 知识点: 3 & 2 = 2,相同为1,不同为0, 011 & 010 = 010:(怎么利用的这个特点不明白):

1151 - Buy or Build(二进制枚举子集 + 并查集)

这题LRJ书上翻译的有问题,书上说两点之间的cost是两点的欧几里得距离,而题目要求两点的距离是两点欧几里得距离的平方. 其余就没什么好说的了,裸的并查集,需要注意的就是二进制枚举子集的问题. 二进制枚举子集: for(int i = 0 ; i < (1 << s) ; i++){ /*s是集合元素的个数*/ for(int j = 0 ; j < s ; j++){ if(!(s >> j) & 1) continue; else{ } } } 140548

UvaLive 6661 Equal Sum Sets 二进制枚举/DP

链接:http://vjudge.net/problem/viewProblem.action?id=49406 题意:根据给出的n,k,s求出n个数每个数都不大于k,和为s的序列(n个数每个都不同)的总情况数. 思路: 1.二进制枚举枚举出所有可能排列,并求和若和为s,则符合,否则不符合. 代码: #include<iostream> #include<set> #include<map> #include<queue> #include<cstri

wikioi 2144 分步二进制枚举+map记录

题目描述 Description 有n个砝码,现在要称一个质量为m的物体,请问最少需要挑出几个砝码来称? 注意一个砝码最多只能挑一次 输入描述 Input Description 第一行两个整数n和m,接下来n行每行一个整数表示每个砝码的重量. 输出描述 Output Description 输出选择的砝码的总数k,你的程序必须使得k尽量的小. 样例输入 Sample Input 3 10 5 9 1 样例输出 Sample Output 2 数据范围及提示 Data Size & Hint 1

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

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

二进制枚举

2017-08-03 11:34:36 writer:pprp 一个知识点,之前从来没有遇到,最近的集训中频繁用到这个,学习理解了 代码及分析如下: // 二进制枚举 // 用来解决例如下边这样的问题 // 给你一串数列,要你将其中所有可能出现的sum找出来,就是说每个数都有两个状态,选或者是不选, //那么就选择用二进制通过 0 1 来表示选还是不选 #include <iostream> using namespace std; int main() { int n; //这里n意思是需要

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条边,先不使用套餐求一遍最小生