hdu 4685 二分匹配+强连通分量
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4685
题解:
这一题是poj 1904的加强版,poj 1904王子和公主的人数是一样多的,并且给出了一个完美匹配,而这一题王子和公主的人数是不同的,而且没有给出任何匹配。因此借鉴1904的做法,我们可以对这题做一些预处理,从而使得它和poj 1904一样能够用强连通分量来求解。
首先求出一个最大匹配,对于每一个没有匹配的王子,加一个虚拟的公主与之匹配,对于每一个没有匹配的公主,加一个虚拟的的王子与之匹配,这样就可以得到一个完美匹配了。并且使得所有的王子都与虚拟的公主连边,所有的公主都与每一个虚拟的王子相连
这样建完图后就可以和poj 1904一样的做法了。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 #include<stack> 6 #include<algorithm> 7 using namespace std; 8 9 const int maxn = 2222; 10 11 int scan() { 12 int ret = 0, flag = 0; char ch; 13 if ((ch = getchar()) == '-') flag = 1; 14 else if (ch >= '0'&&ch <= '9') ret = ch - '0'; 15 while ((ch = getchar()) >= '0'&&ch <= '9') ret = ret * 10 + ch - '0'; 16 return flag ? -ret : ret; 17 } 18 19 void out(int x) { 20 if (x>9) out(x / 10); 21 putchar(x % 10 + '0'); 22 } 23 24 int _t[maxn], lef[maxn]; 25 26 int n, m; 27 28 vector<int> G[maxn],G2[maxn]; 29 30 //二分图的最大匹配----------------------------------------------- 31 bool match(int u) { 32 for (int i = 0; i < G[u].size(); i++) { 33 int v = G[u][i]; 34 if (!_t[v]) { 35 _t[v] = 1; 36 if (lef[v]==-1 || match(lef[v])) { 37 lef[v] = u; 38 return true; 39 } 40 } 41 } 42 return false; 43 } 44 45 void BM() { 46 for (int i = 0; i < n; i++) { 47 memset(_t, 0, sizeof(_t)); 48 match(i); 49 } 50 //for (int i = 0; i < m; i++) { 51 // printf("lef[%d]:%d\n", i + 1, lef[i]+1); 52 //} 53 } 54 //--------------------------------------------------------------- 55 56 //tarjan求强连通---------------------------------------------- 57 int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt; 58 stack<int> S; 59 60 void dfs(int u) { 61 pre[u] = lowlink[u] = ++dfs_clock; 62 S.push(u); 63 for (int i = 0; i < G2[u].size(); i++) { 64 int v = G2[u][i]; 65 if (!pre[v]) { 66 dfs(v); 67 lowlink[u] = min(lowlink[u], lowlink[v]); 68 } 69 else if (!sccno[v]) { 70 lowlink[u] = min(lowlink[u], pre[v]); 71 } 72 } 73 if (lowlink[u] == pre[u]) { 74 scc_cnt++; 75 for (;;) { 76 int x = S.top(); S.pop(); 77 sccno[x] = scc_cnt; 78 if (x == u) break; 79 } 80 } 81 } 82 83 void find_scc(int n) { 84 dfs_clock = scc_cnt = 0; 85 memset(sccno, 0, sizeof(sccno)); 86 memset(pre, 0, sizeof(pre)); 87 for (int i = 0; i < n; i++) { 88 if (!pre[i]) dfs(i); 89 } 90 } 91 //--------------------------------------------------------------- 92 93 94 int vis[maxn]; 95 void solve() { 96 //build 97 memset(vis, 0, sizeof(vis)); 98 int tot_n = n; 99 //构造完美匹配----------------------- 100 for (int i = 0; i < m; i++) { 101 if (lef[i] == -1) { 102 lef[i] = tot_n++; 103 } 104 vis[lef[i]] = 1; 105 } 106 int tot_m = m; 107 for (int i = 0; i < tot_n; i++) { 108 if (vis[i] == 0) lef[tot_m++] = i; 109 } 110 //------------------- 111 112 //每一个王子心仪的公主的连边 113 for (int i = 0; i < n; i++) { 114 for (int j = 0; j < G[i].size(); j++) { 115 int v = G[i][j]; 116 G2[i].push_back(v + tot_n); 117 } 118 } 119 //每一个虚拟的王子与所有的公主的连边 120 for (int i = n; i < tot_n; i++) { 121 for (int v = 0; v < m; v++) { 122 G2[i].push_back(v + tot_n); 123 } 124 } 125 //所有的王子与每一个虚拟公主连边 126 for (int i = m; i < tot_n; i++) { 127 for (int v = 0; v < tot_n; v++) { 128 G2[v].push_back(i+tot_n); 129 } 130 } 131 //每一个公主与和她匹配的那个王子连边 132 for (int i = 0; i < tot_n; i++) { 133 G2[i + tot_n].push_back(lef[i]); 134 } 135 136 //printf("tot_n:%d\n", tot_n); 137 //for (int i = 0; i < tot_n * 2; i++) { 138 // printf("%d:", i + 1); 139 // for (int j = 0; j < G2[i].size(); j++) { 140 // int v = G2[i][j]; v++; 141 // printf("%d ", v); 142 // } 143 // printf("\n"); 144 //} 145 146 //solve 147 find_scc(tot_n*2); 148 149 //for (int i = 0; i < tot_n * 2; i++) { 150 // printf("sccno[%d]:%d\n", i + 1, sccno[i]); 151 //} 152 153 //print 154 for (int i = 0; i < n; i++) { 155 vector<int> ans; 156 for (int j = 0; j < G[i].size(); j++) { 157 int v = G[i][j]; 158 if (sccno[i] == sccno[v + tot_n]) ans.push_back(v); 159 } 160 sort(ans.begin(), ans.end()); 161 out(ans.size()); 162 for (int i = 0; i < ans.size(); i++) { 163 putchar(' '); 164 out(ans[i] + 1); 165 } 166 putchar('\n'); 167 } 168 } 169 170 void init() { 171 for (int i = 0; i < maxn; i++) G[i].clear(),G2[i].clear(); 172 memset(lef, -1, sizeof(lef)); 173 } 174 175 int main() { 176 int tc,kase=0; 177 tc = scan(); 178 while (tc--) { 179 init(); 180 n = scan(); m = scan(); 181 int ct,v; 182 for (int i = 0; i < n; i++) { 183 ct = scan(); 184 for (int j = 0; j < ct; j++) { 185 v = scan(); v--; 186 G[i].push_back(v); 187 } 188 } 189 printf("Case #%d:\n", ++kase); 190 BM(); 191 solve(); 192 } 193 return 0; 194 }