hdu 4685 Prince and Princess(二分匹配+强连通)
这题最开始我是输入n跟m,然后就加入虚拟节点是二分图左右两边节点数一样。。。wa了几发后才知道,加入虚拟节点是根据原图的二分匹配结果M决定的,左边还有x-M个没匹配,右边还有y-M个没匹配,所以这是应加入虚拟节点,使两边节点数为x+y-M,这样才能保证那些原先没有匹配到的王子跟公主也在连通图中。比如两个王子,一个公主,这样的正解应该是两个王子都能娶该公主的。加入的新王子,每个公主都喜欢;加入的新公主,每个王子都喜欢。。好凶残。。然后依次给左右两边未能配对的手动配对(不用再做二分匹配了),左边节点为公主节点,右边为王子。对于u王子,从他配对的v公主,向所有u喜欢却没能配上对的公主节点连边。对这样的一个图求scc,如果两个公主节点再同一个连通分量里面,则说明匹配到这两个公主的两个王子是可以互换公主且不会影响最大匹配对的。
#include<algorithm>#include<iostream>#include<cstring>#include<cstdlib>#include<fstream>#include<sstream>#include<bitset>#include<vector>#include<string>#include<cstdio>#include<cmath>#include<stack>#include<queue>#include<stack>#include<map>#include<set>#define FF(i, a, b) for(int i=a; i<b; i++)#define FD(i, a, b) for(int i=a; i>=b; i--)#define REP(i, n) for(int i=0; i<n; i++)#define CLR(a, b) memset(a, b, sizeof(a))#define debug puts("**debug**")#define LL long long#define PB push_back#define MP make_pairusing namespace std;const int maxn = 1000;int T, n, m, g[maxn][maxn], match[maxn];int uN, vN;bool vis[maxn], use[maxn];bool dfs(int u){ FF(i, 1, vN+1) if(!vis[i] && g[u][i]) { vis[i] = true; if(match[i] == 0 || dfs(match[i])) { match[i] = u; return true; } } return false;}int hungary(){ int ret = 0; CLR(match, 0); FF(i, 1, uN+1) { CLR(vis, 0); if(dfs(i)) ret++; } return ret;}int pre[maxn], low[maxn], dfs_clock, scc_cnt, sccno[maxn];vector<int> G[maxn];stack<int> S;void dfs1(int u){ pre[u] = low[u] = ++dfs_clock; S.push(u); REP(i, G[u].size()) { int v = G[u][i]; if(!pre[v]) { dfs1(v); low[u] = min(low[u], low[v]); } else if(!sccno[v]) low[u] = min(low[u], pre[v]); } if(low[u] == pre[u]) { scc_cnt++; for(;;) { int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } }}void find_scc(int n){ dfs_clock = scc_cnt = 0; CLR(pre, 0); CLR(sccno, 0); FF(i, 1, n+1) if(!pre[i]) dfs1(i);}void build(){ uN = m, vN = n; int M = hungary(); uN = n+m-M, vN = m+n-M; FF(i, m+1, uN+1) FF(j, 1, vN+1) g[i][j] = 1; FF(i, n+1, vN+1) FF(j, 1, uN+1) g[j][i] = 1; CLR(use, 0); int x = m+1; FF(i, 1, n+1) { if(match[i] == 0) match[i] = x++; else use[match[i]] = 1; } x = n+1; FF(i, 1, m+1) if(!use[i]) match[x++] = i;}void solve(int N){ REP(i, N+1) G[i].clear(); FF(i, 1, N+1) FF(j, 1, N+1) if(g[j][i] && j != match[i]) G[match[i]].PB(j); find_scc(N); vector<int> ans; FF(i, 1, n+1) { ans.clear(); FF(j, 1, m+1) if(g[j][i] && sccno[j] == sccno[match[i]]) ans.PB(j); int nc = ans.size(); printf("%d", nc); REP(j, nc) printf(" %d", ans[j]); puts(""); }}int main(){ scanf("%d", &T); FF(kase, 1, T+1) { scanf("%d%d", &n, &m); CLR(g, 0); int x, y; FF(i, 1, n+1) { scanf("%d", &x); while(x--) { scanf("%d", &y); g[y][i] = 1; } } build(); printf("Case #%d:\n", kase); solve(uN); } return 0;}