资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
什么!Anna Locke最近买了几个链环,并且其中的一些链环连接到了一起。它们是由zorkium做成的,这是一种在上世纪经常用来加工珠宝的材料,但它不再用来干这种事了。它有它独特的光泽,即使黄金和白银也无法与之比较,并且无法向任何以前没有见过它的人来描述它。
Anna想要把这些链环拼组成连续的一段链,这个段中的环节首尾相连。她把这些链环带到一个珠宝商那里,珠宝商告诉她合并这些链环的费用取决于必须打开和关上的环的数目。为了最小化这个费用,她小心地计算为了合并成一个单独的序列所需要打开的最小的环的数目。这个比她想象中更困难。你必须为她解决这个问题。
输入格式
输入包含多组关于链环集合的描述,对于每一组。每个链环集合由一行用一个或多个空格隔开的数字表示。每个描述由一个n开始,表示链环集合中环的数量。我们把这些环编号为1,2,…,n。紧接着n后面的整数描述了哪些环连接在一起。每个连接由一对整数i,j(
1<=i,j<=n并且i≠j)来描述,代表环i和环j连接,即一个穿过另一个。每个链环集合用一对-1 -1表示结束(-1 -1 不用进行计算)
输入用n=0表示结束,并且n=0不用进行计算
输出格式
对于每一个输入的链环集合,输出一行形如
Set N: Minimum links to open is M
N的环的个数,M是最小需要打开然后关闭的次数来使所有环组成一条单独的链。
1<=i,j<=n并且i≠j
样例输入
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
样例输出
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
数据规模和约定
1<=n<=15
在这里插入代码片
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int ans,number;
int n;
int map[20][20];
bool sign[20];
bool two(int s)
{
int cnt;
for(int j=0;j<n;j++){
if(s&(1<<j)) //如果该点是被打开的
continue;
cnt=0;
for(int i=0;i<n;i++){
if(map[j][i] && !(s&(1<<i))) //如果这个点连通,并且没有被打开cnt就加1
{
cnt++;
if(cnt==3) return true;
}
}
}
return false;
}
bool dfs(int f,int h,int s) //dfs判断是否存在回路
{
sign[f] = true;
for(int i=0;i<n;i++){
if(map[f][i])
{
if(i==h || (s&(1<<i))) continue; //如果是上一个访问过的, 或者该点被打开,就结束本次循环
if(sign[i]) return true;
if(dfs(i,f,s)) return true;
}
}
return false;
}
bool rycle(int s) //判断是否存在回路
{
memset(sign,false,sizeof(sign));
for(int i=0;i<n;i++){
if(!sign[i] && !(s&(1<<i)))
{
number++; //连通分量的个数
if(dfs(i,-1,s)) return true;
}
}
return false;
}
int count(int s) //计算打开环的个数
{
int cnt=0;
for(int i=0;i<n;i++){
if(s&(1<<i))
cnt++;
}
return cnt;
}
void solve()
{
ans=10000;
for(int i=0;i<(1<<n);i++){ //二进制枚举打开环的所有情况
number=0;
if(two(i) || rycle(i)) //打开相应的环之后,结点的度超过2,或者是个环就不满足条件
continue;
int cnt = count(i); //计算打开环的个数
if(number-1<=cnt)
ans = min(cnt,ans);
}
}
int main()
{
int num=0;
while(cin>>n && n)
{
memset(map,0,sizeof(map));
int a,b;
while(cin>>a>>b && a!=-1 && b!=-1)
{
map[a-1][b-1] = 1;
map[b-1][a-1] = 1;
}
solve();
cout<<"Set "<<++num<<": Minimum links to open is "<<ans<<endl;
}
}