题目: 有n个圆环,其中有一些已经扣在一起了,现在需要打开尽量少的圆环,使得所有的圆环可以组成一条链(当然,所有打开的圆环最后都要再次闭合)。例如,有5个圆环,1-2,2-3,4-5 则需要打开一个圆环4,这样用它穿过3和5 这样就连成1-2-3-4-5
要点;
-
首先得搞明白这个圆环是如何插的,可以想象一下,把4这个圆环从 4-5这个链接中断开后, 4 和 5都是独立的圆环,而一个圆环在插入的时候,事实上是可以链接两条链的,他可以链接 1-2-3 这条原有的链 和 5这条链,因此 如果题目是 给出15个圆环但初始不给任何的链接,那么至少需要7次断开和链接 ,比如 2 链接在 1链和 3链之间,这是题目要搞懂的意思。
-
另外,采用二进制枚举的方式,枚举的到底是链是否断开,还是节点是否断开,这也是需要考虑的问题,以下代码枚举的是节点打开的状态,意思是 例如 1-2 2-3 4-5 我们枚举 1节点断开 其他节点不断开 用 00001 表示 则 00011 表示1和2节点都断开,依次类推。
-
需要注意的是 如果断开后 仍然出现一个节点的分支数大于2的情况,那么不可能称为一条单链,例如 1-2 1-3 1-4 1-5 这个时候断开5
变成 1-2 1-3 1-4 和 5一条单链 由于1链接2,3,4 则不可能链接成一条单链 如若是 1-2 1-3 1-4 断开4 1-2 1-3 4 那么原有的链看成 2-1-3
4插入最左和最右都可以 -
另外还要判环,如果断开节点后仍然成环,那么也是不可以的。
-
最后还要判断现有的链数和断开节点的关系 如果现有的链数为 3 那么至少需要两个断开的节点才能将这个链子连起来。因此要保证断开的节点个数 >= 链数 - 1
-
说的有些啰嗦,因为本人在做这道题的时候,网上很多都没解释清楚,直接扔代码,导致本人也想了挺久的。
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 15 + 5;
int n;
int G[maxn][maxn];
int vis[maxn];
int line;
bool two(int s) {
for(int i = 0; i < n; i++) {
if((s >> i) & 1) continue; //该节点已被打开 等待插环
int cnt = 0;