题目网址点击打开链接
这个题有毒,题意
大概意思应该是:选几个珠子去open。然后该珠子和其他就断开了。然后拿剩下的链去以这些open的珠子为点,去连接,看能不能连成一串。。求最少的open个数。
思路:n为15.利用位运算去枚举哪几个珠子要open。然后判断剩下珠子有没有超过2个分支或者形成环,如果没有,在判断剩下的链个数有没有超过open个数-1.如果条件都符合,那么保留下最小最为答案。
。。。
后来写注释的时候突然发现一个问题对于 f==i这个条件?
出一组样例例如
2
1 2 2 1 -1 -1
按我的对题目的理解答案应该是1;而程序是0
4
1 2 2 1 3 4 4 3
我觉得答案是2 而程序是1
翻了一下大家好像都是这样写的,疑惑中。。。(说不准,某个傻逼又把题意理解错了)
后记:
傻逼,人家不是珠子,人家是环,圆环, 1 2 2 1 就是两个圈圈已经套在了一起,就是个链没差;
1 2 2 1 3 4 4 3 只需解开一个换3 然后把3 和2 4 连上 就是个链(想象一下荧光棒那种圈)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <list>
#include <algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn=20;
const int inf=0x3f3f3f3f;
int vis[maxn];
int eg[maxn][maxn];
int n;
int line;
int two(int s) //求每个点的度数 ,不能大于二
{
int num=0;
for(int i=0;i<n;i++)
{
if(s&(1<<i))
continue;
num=0;
for(int j=0;j<n;j++)
{
if(s&(1<<j))
continue;
if(eg[i][j])
num++;
}
if(num>2)
return 1;
}
return 0;
}
int dfs(int s,int now,int f)
{
vis[now]=1;
for(int i=0;i<n;i++)
{
//突然觉得此处f==i有问题
//f意义之前连过的不能算,比如刚从1-2过来的now=2时,无向图,不能再判一遍2-1(重复)
//断开的珠子不考虑
if(s&(1<<i)||!eg[now][i]||f==i)
continue;
if(vis[i])//如果再次拜访说明
return 1;
if(dfs(s,i,now))
return 1;
}
return 0;
}
//判断有没有圆出现
int cirle(int s)
{
for(int i=0;i<n;i++)
{
if(s&(1<<i)||vis[i])//注意vis过的说明已经在一串链中
continue;
line++;//新链产生
if(dfs(s,i,-1)) //判圆
return 1;
}
return 0;
}
int solve()
{
int ans=inf;
int s=(1<<n);//二级制枚举解开的珠子,1为解开
line=0;
for(int i=0;i<s;i++)
{
line=0;
memset(vis,0,sizeof(vis));
if(two(i)||cirle(i))
continue;
else
{
int res=0;
int k=i;
while(k>0)//open个数
{
res+=k%2;
k/=2;
}
if(res>=line-1)
ans=min(ans,res);
}
}
return ans;
}
int main()
{
int k=0;
while(cin>>n&&n)
{
int a,b;
k++;
memset(eg,0,sizeof(eg));
memset(vis,0,sizeof(vis));
while(cin>>a>>b&&a!=-1&&b!=-1)
{
eg[a-1][b-1]=1;
eg[b-1][a-1]=1;
}
int ans=solve();
if(ans==inf)
ans=0;
printf("Set %d: Minimum links to open is %d\n",k,ans);
}
return 0;
}