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 }

 

posted @ 2016-05-20 02:27  fenicnn  阅读(180)  评论(0编辑  收藏  举报