https://vjudge.net/problem/UVA-818
题意:
有n个圆环,其中有一些已经扣在了一起。现在需要打开尽量少的圆环,使得所有圆环可以组成一条链
n<=15
因为n<=15
二进制枚举子集
1、如果有节点的出度>2,则不能构成链
2、如果有环,则不能构成链
判环方式:有节点被重复访问
3、如果断开环的个数+1<支链的条数,那么不能构成链
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
bool e[16][16],tmp[16][16];
int vis[16],out[16];
int n,ans;
void dfs(int x,int y)
{
for(int i=1;i<=n;i++)
if(tmp[x][i] && i!=y)
{
vis[i]++;
if(vis[i]<2) dfs(i,x);
}
}
void solve(int s)
{
memcpy(tmp,e,sizeof(tmp));
int cnt=0;
for(int i=1;i<=n;i++)
if(s&(1<<i))
{
cnt++;
for(int j=1;j<=n;j++) tmp[i][j]=tmp[j][i]=false;
}
memset(out,0,sizeof(out));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
if(tmp[i][j]) out[i]++;
if(out[i]>2) return;
}
memset(vis,0,sizeof(vis));
int node=0;
for(int i=1;i<=n;i++)
if(!(s&(1<<i)) && !vis[i])
{
vis[i]++; node++;
dfs(i,-1);
}
for(int i=1;i<=n;i++)
if(vis[i]>=2) return;
if(node>cnt+1) return;
ans=min(ans,cnt);
}
int main()
{
int u,v,T=0;
while(1)
{
scanf("%d",&n);
if(!n) return 0;
memset(e,0,sizeof(e));
while(1)
{
scanf("%d%d",&u,&v);
if(u==-1) break;
e[u][v]=e[v][u]=true;
}
ans=15;
int s=1<<15;
for(int i=0;i<s;i++) solve(i);
printf("Set %d: Minimum links to open is %d\n",++T,ans);
}
}