题目:http://poj.org/problem?id=1966
无向图中去掉最少的点使它不连通。
用网络流,割点就是把点变成边再割边。原边的容量为INF防割。
1.因为是无向图,所以拆点的时候应该拆成一个入点和一个出点,保证经过这点的话一定会经过拆出来的这条边。
就可以把点的信息放在这条边上了。即容量为1表示“1个点”。
2.然后遍历起点和终点,更新答案。因为是无向图,所以 j = i + 1 即可。
起点是该点的出点,终点是该点的入点。这样起点和终点都不会被删。于是遍历的时候如果是直接相连的两点就可以continue。
3.需要一些特判。如仅一个点也算连通等等。根据题目提示,只要当ans==INF(初值)的时候输出n就行了。
!重点:找一遍最大流后当前网络会变成残量网络,cap的值都改掉了!所以枚举下一组起点和终点之前要先复原cap!
!!重点:在dinic函数中 if(dfn[v=edge[i].to]==dfn[cr]+1&&edge[i].cap) 这一句中的&&edge[i].cap是不可或缺的!
虽然我觉得在前面的bfs函数里 if(!dfn[v=edge[i].to]&&edge[i].cap) 就已经能限定edge[i].cap了,但去掉dinic里的判断真的会不对!具体为什么呢?
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int INF=250006; int n,m,head[105],dfn[105],xnt,x,y; int mxflow,cur[105],ans,s,t; bool sid[105][105]; struct Edge{ int next,to,cap,w; Edge(int n=0,int t=0,int c=0):next(n),to(t),cap(c),w(c) {} }edge[5105]; queue<int> q; int rd() { char ch; int x=0; ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9') { x=x*10+(int)ch-'0'; ch=getchar(); } return x; } void add(int x,int y,int k) { edge[++xnt]=Edge(head[x],y,k);head[x]=xnt; edge[++xnt]=Edge(head[y],x,0),head[y]=xnt; sid[x][y]=1;sid[y][x]=1; } bool bfs() { memset(dfn,0,sizeof dfn); while(q.size())q.pop(); dfn[s]=1;q.push(s); while(q.size()) { int k=q.front();q.pop(); for(int i=head[k],v;i;i=edge[i].next) if(!dfn[v=edge[i].to]&&edge[i].cap) { dfn[v]=dfn[k]+1;q.push(v); // printf(" v=%d cap=%d ",v,edge[i].cap); if(v==t)return dfn[t]; } } return dfn[t]; } int dinic(int cr,int flow) { if(cr==t)return flow; int used=0; for(int& i=cur[cr],v;i;i=edge[i].next) if(dfn[v=edge[i].to]==dfn[cr]+1&&edge[i].cap)///////////!!!!!!!!!! { // printf(" flow=%d cap=%d ",flow,edge[i].cap); int tmp=dinic(v,min(flow-used,edge[i].cap)); if(!tmp)dfn[v]=0; used+=tmp; edge[i].cap-=tmp; edge[i^1].cap+=tmp; // printf("tmp=%d ",tmp); if(used==flow)break; } return used; } int main() { while(scanf("%d%d",&n,&m)==2) { xnt=1;ans=INF; memset(head,0,sizeof head); for(int i=0;i<n;i++)add(i,n+i,1); for(int i=1;i<=m;i++) { x=rd();y=rd(); add(x+n,y,INF);add(y+n,x,INF); } for(int i=0;i<n;i++) for(t=i+1;t<n;t++) { if(sid[i+n][t])continue; s=i+n; mxflow=0; for(int i=2;i<=xnt;i++)edge[i].cap=edge[i].w; while(bfs()) { memcpy(cur,head,sizeof head); mxflow+=dinic(s,INF); } ans=min(ans,mxflow); // printf("(%d)",ans); } if(ans==INF)ans=n; printf("%d ",ans); } return 0; }