D . Cutting Chains

Description

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 has its very own shine, incomparable to gold or silver, and impossible to describe to anyone who has not seen it first hand.

Anna wants the pieces joined into a single end-to-end strand of chain. She takes the links to a jeweler who tells her that the cost of joining them depends on the number of chain links that must be opened and closed. In order to minimize the cost, she carefully calculates the minimum number of links that have to be opened to rejoin all the links into a single sequence. This turns out to be more difficult than she at first thought. You must solve this problem for her.

Input

The input consists of descriptions of sets of chain links, one set per line. Each set is a list of integers delimited by one or more spaces. Every description starts with an integer nn, which is the number of chain links in the set, where 1≤n≤151≤n≤15. We will label the links 1,2,…,n1,2,…,n. The integers following nn describe which links are connected to each other. Every connection is specified by a pair of integers i,ji,j where 1≤i,j≤n1≤i,j≤n and i=ji=j, indicating that chain links ii and jj are connected, i.e., one passes through the other. The description for each set is terminated by the pair ‘-1 -1’, which should not be processed.

The input is terminated by a description starting with n=0n=0. This description should not be processed and will not contain data for connected links.

Output

For each set of chain links in the input, output a single line which reads

Set NN: Minimum links to open is MM

where NN is the set number and MM is the minimal number of links that have to be opened and closed such that all links can be joined into one single chain.

Samples

Input

5 1 2 2 3 4 5 -1 -1
7 1 2 2 3 3 1 4 5 5 6 6 7 7 4 -1 -1
4 1 2 1 3 1 4 -1 -1
3 1 2 2 3 3 1 -1 -1
3 1 2 2 1 -1 -1
0

Output

Set 1: Minimum links to open is 1
Set 2: Minimum links to open is 2
Set 3: Minimum links to open is 1
Set 4: Minimum links to open is 1
Set 5: Minimum links to open is 1

题目大意:给出一些环以及那些环之间是相连的,问所最少打开即可环,可以将这些环连成一串,注意不是环

思路:

首先明确目标:

图中不可能存在度为3或者以上的结点
图中不可能存在环
图肯定是连通的
我们打开一个环,可以暂时把它拿出来,不去管它,因为如果除了它,其余结点的图满足上述要求,则把这个环放在末尾即可;如果拿掉打开的环以后,图分为了两个图,如果这两个图都满足上述要求,那么可以用这个环把这两个连通分量连接为一个(连通分量个数 <= 打开的环数-1)。

好,我们更新一下目标,允许目标图不连通:

图中不可能存在度为3或者以上的结点(遍历图)
图中不可能存在环(dfs 搜索)
连通分量个数 <=打开的环数-1(dfs 搜索)

#include<bits/stdc++.h>
using namespace std;
int n, cnt, number;
int e[20][20];		//用邻接矩阵存储
int vis[20];
int ans;
int two(int s) { //判断是否有度数数大于2的圆环
	for (int i=0; i<n; i++) {
		int cnt=0;  //记录度数
		for (int j=0; j<n; j++)
			//如果圆环i和j连通并且没有打开i或j时,i圆环的分支数+1
			if (e[i][j]&&!(s&(1<<i))&&!(s&1<<j)) {
				cnt++;
				if(cnt==3)
					return 1;
			}
	}
	return 0;
}

int dfs(int x, int f, int s) { //判断是否有回路存在
	vis[x]=1;
	for (int i=0; i<n; i++)
		if (e[x][i]) {
			if(i==f||(s&(1<<i)))
				continue;  //如果i是上一次访问的圆环或者i圆环被打开,进行下一次判定
			if(vis[i])
				return 1;  //存在回路
			if (dfs(i,x,s))
				return 1;
		}
	return 0;
}

int circle(int s) {	//判断是否有环出现,同时记录连通分量数
	memset(vis,0,sizeof(vis));
	for (int i=0; i<n; i++)
		if (!vis[i]&&!(s&(1<<i))) {
			number++;   	//连通分量数+1
			if (dfs(i,-1,s))
				return 1;
		}
	return 0;
}

int calc(int s) { //计算出打开圆环的个数
	int cnt = 0;
	for (int j = 0; j < n; j++)
		if (s&(1<<j))
			cnt++;	//位运算
	return cnt;
}

void solve() {
	ans=100000;
	for(int i=0; i<(1<<n); i++) { //二进制枚举打开圆环的情况
		number=0;
		if (two(i)||circle(i))
			continue;  //如果不行,进行下一次判断,如果不存在两个分支或回路,则正好计算出了连通分支数
		int count=calc(i);
		if (number-1<=count)   //连通分支数-1<=打开的圆环数
			ans=min(ans,count);
	}
}

int main() {
	int a,b,kase=0;
	cin>>n;
	while (n) {
		memset(e, 0, sizeof(e));
		cin>>a>>b;
		while (a!=-1&&b!=-1) {
			e[a-1][b-1]=1;
			e[b-1][a-1]=1;
			cin>>a>>b;
		}
		solve();
		cout<<"Set "<<++kase<<": Minimum links to open is "<<ans<<endl;
		cin>>n;
	}
	return 0;
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值