hdu 4685 二分匹配+强连通分量

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4685

题解:

  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 bool match(int u) {
 31     for (int i = 0; i < G[u].size(); i++) {
 32         int v = G[u][i];
 33         if (!_t[v]) {
 34             _t[v] = 1;
 35             if (lef[v]==-1 || match(lef[v])) {
 36                 lef[v] = u;
 37                 return true;
 38             }
 39         }
 40     }
 41     return false;
 42 }
 43
 44 void BM() {
 45     for (int i = 0; i < n; i++) {
 46         memset(_t, 0, sizeof(_t));
 47         match(i);
 48     }
 49     //for (int i = 0; i < m; i++) {
 50     //    printf("lef[%d]:%d\n", i + 1, lef[i]+1);
 51     //}
 52 }
 53
 54 int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
 55 stack<int> S;
 56
 57 void dfs(int u) {
 58     pre[u] = lowlink[u] = ++dfs_clock;
 59     S.push(u);
 60     for (int i = 0; i < G2[u].size(); i++) {
 61         int v = G2[u][i];
 62         if (!pre[v]) {
 63             dfs(v);
 64             lowlink[u] = min(lowlink[u], lowlink[v]);
 65         }
 66         else if (!sccno[v]) {
 67             lowlink[u] = min(lowlink[u], pre[v]);
 68         }
 69     }
 70     if (lowlink[u] == pre[u]) {
 71         scc_cnt++;
 72         for (;;) {
 73             int x = S.top(); S.pop();
 74             sccno[x] = scc_cnt;
 75             if (x == u) break;
 76         }
 77     }
 78 }
 79
 80 void find_scc(int n) {
 81     dfs_clock = scc_cnt = 0;
 82     memset(sccno, 0, sizeof(sccno));
 83     memset(pre, 0, sizeof(pre));
 84     for (int i = 0; i < n; i++) {
 85         if (!pre[i]) dfs(i);
 86     }
 87 }
 88
 89 int vis[maxn];
 90 void solve() {
 91     //build
 92     memset(vis, 0, sizeof(vis));
 93     int tot_n = n;
 94     for (int i = 0; i < m; i++) {
 95         if (lef[i] == -1) {
 96             lef[i] = tot_n++;
 97         }
 98         vis[lef[i]] = 1;
 99     }
100     int tot_m = m;
101     for (int i = 0; i < tot_n; i++) {
102         if (vis[i] == 0) lef[tot_m++] = i;
103     }
104     for (int i = 0; i < n; i++) {
105         for (int j = 0; j < G[i].size(); j++) {
106             int v = G[i][j];
107             G2[i].push_back(v + tot_n);
108         }
109     }
110     for (int i = n; i < tot_n; i++) {
111         for (int v = 0; v < m; v++) {
112             G2[i].push_back(v + tot_n);
113         }
114     }
115     for (int i = m; i < tot_n; i++) {
116         for (int v = 0; v < tot_n; v++) {
117             G2[v].push_back(i+tot_n);
118         }
119     }
120     for (int i = 0; i < tot_n; i++) {
121         G2[i + tot_n].push_back(lef[i]);
122     }
123
124     //printf("tot_n:%d\n", tot_n);
125     //for (int i = 0; i < tot_n * 2; i++) {
126     //    printf("%d:", i + 1);
127     //    for (int j = 0; j < G2[i].size(); j++) {
128     //        int v = G2[i][j]; v++;
129     //        printf("%d ", v);
130     //    }
131     //    printf("\n");
132     //}
133
134     //solve
135     find_scc(tot_n*2);
136
137     //for (int i = 0; i < tot_n * 2; i++) {
138     //    printf("sccno[%d]:%d\n", i + 1, sccno[i]);
139     //}
140
141     //print
142     for (int i = 0; i < n; i++) {
143         vector<int> ans;
144         for (int j = 0; j < G[i].size(); j++) {
145             int v = G[i][j];
146             if (sccno[i] == sccno[v + tot_n]) ans.push_back(v);
147         }
148         sort(ans.begin(), ans.end());
149         out(ans.size());
150         for (int i = 0; i < ans.size(); i++) {
151             putchar(‘ ‘);
152             out(ans[i] + 1);
153         }
154         putchar(‘\n‘);
155     }
156 }
157
158 void init() {
159     for (int i = 0; i < maxn; i++) G[i].clear(),G2[i].clear();
160     memset(lef, -1, sizeof(lef));
161 }
162
163 int main() {
164     int tc,kase=0;
165     tc = scan();
166     while (tc--) {
167         init();
168         n = scan(); m = scan();
169         int ct,v;
170         for (int i = 0; i < n; i++) {
171             ct = scan();
172             for (int j = 0; j < ct; j++) {
173                 v = scan(); v--;
174                 G[i].push_back(v);
175             }
176         }
177         printf("Case #%d:\n", ++kase);
178         BM();
179         solve();
180     }
181     return 0;
182 }
时间: 2024-10-04 21:23:21

hdu 4685 二分匹配+强连通分量的相关文章

H - Prince and Princess - HDU 4685(二分匹配+强连通分量)

题意:有N个王子M个公主,王子喜欢一些公主,而且只能是王子喜欢的人,他们才可以结婚,现在让他们尽可能多的结婚的前提下找出来每个王子都可以和谁结婚. 分析:先求出来他们的最大匹配,因为给的数据未必是完备匹配,所以需要添加一些点使他们成为完备匹配才能求出来的环是完整的,比如第二组数据: 1 2   2 1 2 如果不添加虚拟点做成匹配,只会匹配成功一个,这样就找不出来环了,所以需要添加虚拟的王子和公主,虚拟的王子喜欢所有的公主,虚拟的公主被所有的王子喜欢,注意都是王子喜欢公主的,公主没有选择喜欢的权

【连通图|二分匹配+强连通分量】POJ-1904 King&#39;s Quest

King's Quest Time Limit: 15000MS Memory Limit: 65536K Case Time Limit: 2000MS Description Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those g

Prince and Princess HDU - 4685(匹配 + 强连通)

Prince and Princess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 2336    Accepted Submission(s): 695 Problem Description There are n princes and m princesses. Princess can marry any prince. B

Hdu 2389 二分匹配

题目链接 Rain on your Parade Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 655350/165535 K (Java/Others)Total Submission(s): 2644    Accepted Submission(s): 823 Problem Description You’re giving a party in the garden of your villa by the sea. T

UESTC 898 方老师和缘分 --二分图匹配+强连通分量

这题原来以为是某种匹配问题,后来好像说是强连通的问题. 做法:建图,每个方老师和它想要的缘分之间连一条有向边,然后,在给出的初始匹配中反向建边,即如果第i个方老师现在找到的是缘分u,则建边u->i.这样求出所有的强连通分量,每个强连通分量中方老师和缘分的数目一定是相等的,所以每个方老师一定可以找到与他在同一个强连通分量里的缘分,因为强连通分量中每个点都是可达的,某个方老师找到了其强连通分量中的非原配点,则该原配缘分一定可以在强连通分量中找到"新欢".可以画个图看看. 由于要构造非

HDU 3639 Hawk-and-Chicken (强连通分量+树形DP)

题目地址:HDU 3639 先用强连通分量缩点,缩点之后,再重新按缩点之后的块逆序构图,每个块的值是里边缩的点的个数,那么得到选票的最大的一定是重新构图后入度为0的块,然后求出来找最大值即可. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h>

poj1904 二分图匹配+强连通分量

http://poj.org/problem?id=1904 Description Once upon a time there lived a king and he had N sons. And there were N beautiful girls in the kingdom and the king knew about each of his sons which of those girls he did like. The sons of the king were you

hdu 3639 Hawk-and-Chicken 【强连通分量+反向建图dfs】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3639 题意:有n个人,m条边,每条边代表u给v投一票,票可以传递,比如A->B,B->C,这时C可以得到2票,求出得到最大票数的人有哪些. 分析:从一个强连通到另一个强连通分量的贡献为这两个强连通分量大小和减一.显然票数最大的人在图的端点. 将缩点后的图方向,可以得到一些入度为0的点,用DFS可以求出这些点的票数,最后去求出最大票数. 代码: <pre name="code"

hdu 4169 二分匹配最大独立集 ***

题意:有水平N张牌,竖直M张牌,同一方向的牌不会相交.水平的和垂直的可能会相交,求最少踢出去几张牌使剩下的牌都不相交. 二分匹配 最小点覆盖=最大匹配. 链接:点我 坐标点作为匹配的端点 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #incl