题目大意:给一张n个点、m条边的无向图,求最小点割集的基数。
题目分析:求无向图最小点割集的基数可以变成求最小割。考虑单源s单汇t的无向图,如果要求一个最小点集,使得去掉这个点集后图不再连通(连通分量数目增多),只需将每个点拆成两个(入点和出点),并且之间连一条容量为1的弧,其他弧不变,在新网络上求最小割便得到这个最小点集的基数。但是本题无源无汇,可以指定一个点作为源点,枚举其它的点作为汇点,求得n-1个点集基数,取最小的便是答案。要注意每次枚举都要重新建图。
代码如下:
# include<iostream> # include<cstdio> # include<vector> # include<queue> # include<cstring> # include<algorithm> using namespace std; const int INF=1<<30; const int maxn=105; struct Edge { int fr,to,cap,fw; Edge(int fr,int to,int cap,int fw){ this->fr=fr; this->to=to; this->cap=cap; this->fw=fw; } }; struct Dinic { vector<Edge>edges; vector<int>G[maxn]; int d[maxn],cur[maxn]; int vis[maxn],n,s,t; void init(int n) { this->n=n; edges.clear(); for(int i=0;i<n;++i) G[i].clear(); } void addEdge(int u,int v,int cap) { edges.push_back(Edge(u,v,cap,0)); edges.push_back(Edge(v,u,0,0)); int m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } bool bfs() { memset(vis,0,sizeof(vis)); vis[s]=1; d[s]=0; queue<int>q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<G[u].size();++i){ Edge& e=edges[G[u][i]]; if(e.cap>e.fw&&!vis[e.to]){ vis[e.to]=1; d[e.to]=d[u]+1; q.push(e.to); } } } return vis[t]; } int dfs(int u,int a) { if(u==t||a==0) return a; int flow=0,f; for(int &i=cur[u];i<G[u].size();++i){ Edge& e=edges[G[u][i]]; if(d[e.to]==d[u]+1&&(f=dfs(e.to,min(a,e.cap-e.fw)))>0){ e.fw+=f; edges[G[u][i]^1].fw-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int maxFlow(int s,int t) { this->s=s,this->t=t; int flow=0; while(bfs()){ memset(cur,0,sizeof(cur)); flow+=dfs(s,INF); } return flow; } }; Dinic solver; string p; int n,m,mark[55]; vector<Edge>E; void addEdge(int u,int v,int cap) { E.push_back(Edge(u,v,cap,0)); } void solve() { int len=p.size(),pos; for(pos=0;pos<len;++pos) if(p[pos]==',') break; int a=0,b=0; for(int i=1;i<pos;++i) a=a*10+p[i]-'0'; for(int i=pos+1;i<len-1;++i) b=b*10+p[i]-'0'; addEdge(a<<1|1,b<<1,INF); addEdge(b<<1|1,a<<1,INF); } void look() { for(int i=0;i<solver.edges.size();++i){ Edge& e=solver.edges[i]; cout<<e.fr<<' '<<e.to<<' '<<e.cap<<' '<<e.fw<<endl; } } int main() { int a,b; while(~scanf("%d%d",&n,&m)) { E.clear(); for(int i=0;i<n;++i) addEdge(i<<1,i<<1|1,1); while(m--) { cin>>p; solve(); } //look(); int ans=n,k=E.size(); for(int i=1;i<n;++i){ solver.init(n*2); for(int j=0;j<k;++j){ solver.addEdge(E[j].fr,E[j].to,E[j].cap); } int flow=solver.maxFlow(1,i<<1); ans=min(ans,flow); } printf("%d ",ans); } return 0; }