求无向图的点连通分量,把一个点拆成一个入点和一个出点,之间连一条容量为1的有向边,表示能被用一次。最大流求最小割即可。
一些细节的东西:1.源点固定,汇点要枚举一遍,因为最小割割断以后会形成连通分量,在源点的那个连通分量里的割会更大。
2.每次枚举重建一下图。3.从入点进出点出就被认为是经过了一个原来的点,那么源点和汇点是不必经过的,所以一个在出点,另外一个枚举入点。
#include<bits/stdc++.h> using namespace std; const int maxn = 102; struct Edge { int v,cap,nxt; }; vector<Edge> E; vector<Edge> bak; #define PB push_back int head[maxn]; void AddEdge(int u,int v,int c) { bak.PB({v,c,head[u]}); head[u] = bak.size()-1; bak.PB({u,0,head[v]}); head[v] = bak.size()-1; } int S,T,cur[maxn],d[maxn],q[maxn]; bool bfs() { memset(d,0,sizeof(d)); int l = 0, r = 0; q[r++] = S; d[S] = 1; while(r>l){ int u = q[l++]; for(int i = head[u]; ~i; i = E[i].nxt){ Edge &e = E[i]; if(!d[e.v] && e.cap>0){ d[e.v] = d[u] + 1; q[r++] = e.v; } } } return d[T]; } int dfs(int u,int a) { if(u == T||!a) return a; int flow = 0,f; for(int &i = cur[u]; ~i; i = E[i].nxt){ Edge &e = E[i]; if(d[e.v] == d[u]+1 && (f = dfs(e.v,min(a,e.cap)))>0){ flow += f; a -= f; e.cap -= f; E[i^1].cap += f; if(!a) break; } } return flow; } const int INF = 0x3f3f3f3f; int MaxFlow() { int flow = 0; while(bfs()){ memcpy(cur,head,sizeof(head)); flow += dfs(S,INF); } return flow; } int n,m; void init() { memset(head,-1,sizeof(head)); bak.clear(); } int main() { //freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)){ init(); for(int i = 1; i < n; i++) AddEdge(i,i+n,1); for(int i = 0; i < m; i++){ int u,v; scanf(" (%d,%d)",&u,&v); AddEdge(u+n,v,INF); AddEdge(v+n,u,INF); } int ans = n; S = n; for(T = 1; T < n; T++){ E = bak; ans = min(ans,MaxFlow()); } printf("%d\n",ans); } return 0; }
时间: 2024-11-08 22:18:25