传送门:>Here<
题意:二分图匹配输出方案
思路分析
学会了最大流再也不用敲匈牙利了哈哈……
最大流可以直接解决二分图匹配问题,方法是:将左侧节点与右侧节点的无向边全都变为容量为1的弧(正反),源点一一连向左侧节点,右侧节点一一连向汇点。跑最大流即可
关于为什么这样做是正确的,可以参见算法导论中有严格的证明。但其实这是一目了然的,由于所有弧的容量都为1,从源点连向左侧节点也就意味着最多只有1的流量到达每个节点。这个1就代表了这个节点只能被匹配一次。而右侧节点到汇点的容量也是1,意味着右侧节点也只能被匹配一次。在这样的约束条件下的最大流就是最大匹配了
关于输出方案则更简单,由于前面提到了容量都是1,所以一个点出发肯定只有一条有流量的弧,且流量=容量=1。所以求解最大匹配的方案实际上就是在左右两侧节点之间的弧内取出所有的有流量的弧。所有有流量的弧即为答案
Code
注意因为要统计答案,邻接表在存储的时候还要多加一个from记录起点
/*By DennyQi*/ #include <cstdio> #include <queue> #include <cstring> #include <algorithm> #define r read() #define Max(a,b) (((a)>(b)) ? (a) : (b)) #define Min(a,b) (((a)<(b)) ? (a) : (b)) using namespace std; typedef long long ll; const int MAXN = 1010; const int MAXM = 10010; const int INF = 1061109567; inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); return x * w; } int M,N,S,T,x,y,_begin; int first[MAXM*2],nxt[MAXM*2],from[MAXM*2],to[MAXM*2],cap[MAXM*2],flow[MAXM*2],num_edge=-1; int level[MAXN],cur[MAXN]; queue <int> q; inline void add(int u, int v, int c, int f){ to[++num_edge] = v; cap[num_edge] = c; flow[num_edge] = f; from[num_edge] = u; nxt[num_edge] = first[u]; first[u] = num_edge; } inline bool BFS(){ memset(level, 0, sizeof(level)); while(!q.empty()) q.pop(); q.push(S); level[S] = 1; int u,v; while(!q.empty()){ u = q.front(); q.pop(); for(int i = first[u]; i != -1; i = nxt[i]){ v = to[i]; if(!level[v] && cap[i]-flow[i] > 0){ level[v] = level[u] + 1; q.push(v); } } } return level[T]!=0; } int DFS(int u, int a){ if(u == T || a == 0) return a; int ans=0,v,_f; for(int& i = cur[u]; i != -1; i = nxt[i]){ v = to[i]; if(level[u]+1==level[v] && cap[i]>flow[i]){ _f = DFS(v, Min(a, cap[i]-flow[i])); ans += _f, a -= _f; flow[i] += _f, flow[i^1] -= _f; if(a == 0) break; } } return ans; } inline void Dinic(){ int tot = 0; while(BFS()){ for(int i = S; i <= T; ++i) cur[i] = first[i]; tot += DFS(S, INF); } printf("%d ", tot); } int main(){ freopen(".in","r",stdin); M=r,N=r; memset(first, -1, sizeof(first)); S=0, T=N+1; for(int i = 1; i <= M; ++i){ add(S, i, 1, 0); add(i, S, 0, 0); } for(int i = M+1; i <= N; ++i){ add(i, T, 1, 0); add(T, i, 0, 0); } _begin = num_edge + 1; for(;;){ x=r, y=r; if(x==-1 && y==-1) break; add(x, y, 1, 0); add(y, x, 0, 0); } Dinic(); for(int i = _begin; i <= num_edge; ++i){ if(cap[i]-flow[i] == 0 && cap[i]==1){ printf("%d %d ", from[i], to[i]); } } return 0; }