uva818 Cutting Chains
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93788#problem/D
#include<bits/stdc++.h> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) memset(a,0,sizeof(a)) #define PB push_back using namespace std; typedef long long ll; const int maxn=1000100; const int INF=(1<<29); int n; vector<int> G[20]; int cnt[1<<17]; int kai; int u,v; bool vis[20]; int g[20][20]; int dfs(int u,int f) { //cout<<"u="<<u<<" f="<<f<<endl; vis[u]=1; int tag=2; for(int i=0;i<G[u].size();i++){ int v=G[u][i]; if(kai&(1<<v)) continue; if(v==f) continue; if(vis[v]) return 0; //cout<<"tag="<<tag<<" uu="<<u<<" v="<<v<<endl; if(u==f){ if(tag==0) return 0; } else if(tag==1) return 0; int tmp=dfs(v,u); if(tmp==0) return 0; tag--; } //cout<<"u="<<u<<endl; return 1; } int solve() { MS0(vis); int link=0; REP(i,0,n-1){ if((kai&(1<<i))||vis[i]) continue; if(!dfs(i,i)) return INF; else link++; } //cout<<"kai="<<kai<<" cnt="<<cnt[kai]<<" link="<<link<<endl; return cnt[kai]>=link-1?cnt[kai]:INF; } int Cnt(int n) { int res=0; while(n){ res+=n%2; n>>=1; } return res; } void Init() { REP(i,0,(1<<17)-1) cnt[i]=Cnt(i); } int main() { freopen("in.txt","r",stdin); Init();int casen=1; while(cin>>n,n){ REP(i,0,n-1) G[i].clear(); MS0(g); while(~scanf("%d%d",&u,&v)&&~u&&~v){ u--;v--; if(g[u][v]) continue; g[u][v]=g[v][u]=1; G[u].PB(v);G[v].PB(u); } int ans=n; for(kai=0;kai<(1<<n);kai++){ if(cnt[kai]>=ans) continue; int tmp=solve(); //cout<<kai<<" "<<tmp<<endl<<endl; ans=min(tmp,ans); } printf("Set %d: Minimum links to open is %d ",casen++,ans); } return 0; } /** 题意: 给一些扣在一起的圆环,构成的图,不一定连通,求打开最少的圆环使所有的圆环连成一条链。打开一个圆环消耗一单位,闭合圆环不消耗。 圆环个数1<=n<=15 思路: n<=15,可以用二进制压缩状态,1表示打开的圆环。打开一些圆环,剩下的圆环必须是若干条链才能连成长链,而连接k条链需要k-1个打开的圆环。 因此只需枚举打开哪些圆环,然后判断能否连成链,最后更新下答案即可。 类型: 枚举。 注意事项: 注意判断链的时候开始搜的点有可能是链的端点也可能不是。 坑点: 同一条边居然会输入多次。。。。。。 */