POJ 1904 King's Quest (强连通分量+完美匹配)
<题目链接>
题目大意:
有n个王子,每个王子都有k个喜欢的妹子,每个王子只能和喜欢的妹子结婚,大臣给出一个匹配表,每个王子都和一个妹子结婚,但是国王不满意,他要求大臣给他另一个表,每个王子可以和几个妹子结婚,按序号升序输出妹子的编号,这个表应满足所有的王子最终都有妹子和他结婚。
解题分析: <转载于 >>> >
如果王子u喜欢妹子v,则建一条边u指向v(u,v),对于大臣给出的初始完美匹配,如果王子u和妹子v结婚,则建一条边v指向u(v,u),然后求强连通分量。对于每个王子和妹子,如果他们都在同一个强连通分量内,则他们可以结婚。
为什么呢?因为每个王子只能和喜欢的妹子结婚,初始完美匹配中的丈夫和妻子之间有两条方向不同的边可以互达,则同一个强连通分量中的王子数和妹子数一定是相等的,若王子 x 可以和另外的一个妹子 a 结婚,妹子 a 的原配王子 y 肯定能找到另外一个妹子 b 结婚,因为如果找不到的话,则 x 和 a 必不在同一个强连通分量中。
所以一个王子可以和所有与他同一强连通分量的妹子结婚,而这不会导致同一强连通分量中的其他王子找不到妹子结婚。
(证明:王子为什么不能选择不同强连通分量的妹子:
反证法:如果强连通分量 1 中的王子选择了强连通分量 2 中的妹子,那么势必强连通分量 2 中的一个王子无法在自己的强连通分量中找到妹子,那么他就会去别的强连通分量找妹子,这样一直循环下去,我们知道最终一定是经过了强连通分量 1,2,x1,x2,xn,……,1,王子们才能都找到自己的妹子,这样这些强连通分量1,2,x1,x2,xn,……,1会构成一个强连通分量,与题设在不同强连通分量中找妹子不符)。
#include <algorithm> #include <cstdio> #include <cstring> #include <vector> using namespace std; #define clr(a, b) memset(a, b, sizeof(a)) const int N = 5e3 + 10; int n, tot, scc, top; int stk[N], dfn[N], low[N], belong[N], instack[N], ans[N]; vector<vector<int> > G; void init() { tot = scc = top = 0; clr(dfn, 0);clr(stk, 0);clr(low, 0);clr(belong, 0);clr(instack, 0); G.clear(), G.resize(N); } void Tarjan(int u) { low[u] = dfn[u] = ++tot; stk[++top] = u; instack[u] = 1; int v; for (int i = 0; i < G[u].size(); i++) { v = G[u][i]; if (!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if (instack[v]) low[u] = min(low[u], dfn[v]); } if (low[u] == dfn[u]) { ++scc; do { v = stk[top--]; instack[v] = 0; belong[v] = scc; //将该强连通块缩点染色 } while (v != u); } } int main() { while (scanf("%d", &n) != EOF) { init(); int k, x; for (int i = 1; i <= n; i++) { scanf("%d", &k); while (k--) { scanf("%d", &x); G[i].push_back(x + n); //王子编号为1~n,公主编号为n+1~2*n } } for (int i = 1; i <= n; i++) { scanf("%d", &x); G[x + n].push_back(i); //根据该完美匹配,让公主与对应的王子连边 } for (int i = 1; i <= n; i++) if (!dfn[i]) Tarjan(i); for (int i = 1; i <= n; i++) { int u = belong[i], v; clr(ans, 0); // ans[]存所有能够与当前王子进行配对的公主 int cur = 0; for (int j = 0; j < G[i].size(); j++) { //找出当前王子所在联通块的公主数量 v = belong[G[i][j]]; if (u == v) ans[cur++] = G[i][j]; } sort(ans, ans + cur); printf("%d ", cur); for (int i = 0; i < cur; i++) { printf("%d%s", ans[i] - n, i == cur - 1 ? "\n" : " "); } } } }
作者:is_ok
出处:http://www.cnblogs.com/00isok/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。