题意就是给一张无向图,去掉某些结点,然后连成一条链,问最少去掉几个结点。
n很小n<=15,所以直接枚举2^15个状态就行啦。
链的条件是1.无环,2.没有度大于2的点,3.把n个散链连起来需要n-1次拼接,去掉的结点数>=n-1。
#include<bits/stdc++.h> using namespace std; const int maxn = 15; int G[maxn][maxn]; int n; int c[maxn]; bool dfs(int u,int s,int fa) { c[u] = 1; for(int v = 0; v < n; v++) if(!((s>>v)&1) && G[u][v] && v != fa) { if(c[v] || dfs(v,s,u)) return true; } return false; } int cn; bool have_circle(int s) { memset(c,0,sizeof(c)); for(int i = 0;i < n; i++) if(!((s>>i)&1) && !c[i] ){ cn++; if(dfs(i,s,-1)) return true; } return false; } bool two(int s) { for(int i = 0; i < n; i++) if(!((s>>i)&1)) { int deg = 0; for(int j = 0; j < n; j++) if(!((s>>j)&1) && G[i][j]) { deg++; } if(deg>2) return true; } return false; } int cal(int s,int &t){ t = 0; while(s){ if(s&1) t++; s>>=1; } return t; } int main() { //freopen("in.txt","r",stdin); int cas = 0; while(~scanf("%d",&n)&&n){ int u,v; memset(G,0,sizeof(G)); while(~scanf("%d%d",&u,&v)&~u){ G[u-1][v-1] = G[v-1][u-1] = 1; } int ans = 233; for(int s = 0,sz = 1<<n; s < sz; s++){ cn = 0; if(!two(s) && !have_circle(s)){ int t; if(cn-1 <= cal(s,t)) ans = min(ans,t); } } printf("Set %d: Minimum links to open is %d\n", ++cas, ans); } return 0; }