稳定婚姻的判定问题。
老实说,写了几题后发现稳定婚姻问题几乎都是板子题……囧……
而且我作为入门题写的那道题好歹还披了一件外套,有几道完完全全的裸题写得我是非常的空虚……
回到这道题,这道题应该算是稳定婚姻判定的裸题了。
假如我们再次无脑套模板,复杂度还是在( O(n^2) )左右。
我们从另一个角度来考虑。如果我可以找到一个相互出轨的夫妻,那就是不稳定的。
从而,对于一个已知的婚姻匹配,如果存在一对夫妻离婚,但不会对其他夫妻造成任何影响,那么这组婚姻匹配就是稳定的。
稳定婚姻的判定就是通过这种方式找到可以相互出轨的夫妻。
一个可行解法就是求强联通分量。对于已知匹配建立好单向二分图,对于可出轨匹配用反向边表示。然后求一下强联通分量。如果存在一组匹配,他们被染色的数量超过 ( 1 ) 是什么颜色呢??
那这个婚姻匹配就是不稳定的。
复杂度为Tarjan的复杂度,估计在( O( n ) ) 左右。
题意:
先给你一组婚姻匹配,再给你几组可出轨匹配,问你对于每一对夫妻,他们的匹配是否安全。
思路:
裸题啦,裸题,看了我上面的陈述就知道该怎么写了。
AC Code
#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define each(i, n) for (int(i) = 0; (i) < (n); (i)++)
#define reach(i, n) for (int(i) = n - 1; (i) >= 0; (i)--)
#define range(i, st, en) for (int(i) = (st); (i) <= (en); (i)++)
#define rrange(i, st, en) for (int(i) = (en); (i) >= (st); (i)--)
#define fill(ary, num) memset((ary), (num), sizeof(ary))
using namespace std;
const int maxn = 8005;
const int maxm = 3e4 + 5;
int n, m;
map<string, int> man, woman;
string rman[maxn], rwoman[maxn];
int head[maxn], idx;
struct node {
int to;
int next;
} edges[maxm];
void addEdge(int u, int v)
{
edges[idx] = (node){ v, head[u] };
head[u] = idx++;
}
int scc, top, vis_time;
int dfn[maxn], low[maxn], in[maxn], color[maxn], st[maxn], color_num[maxn];
bool instack[maxn];
void init()
{
man.clear(), woman.clear();
for (int i = 0; i <= 2 * n; i++) {
head[i] = -1;
in[i] = dfn[i] = low[i] = 0;
}
vis_time = top = idx = scc = 0;
}
void tarjan(int u)
{
int v;
low[u] = dfn[u] = vis_time++;
instack[u] = true;
st[++top] = u;
for (int id = head[u]; ~id; id = edges[id].next) {
v = edges[id].to;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (instack[v])
low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
color_num[++scc] = 0;
do {
v = st[top--];
instack[v] = false;
color_num[scc]++;
color[v] = scc;
} while (v != u);
}
}
int main()
{
ios::sync_with_stdio(false);
string u, v;
while (cin >> n) {
init();
range(i, 1, n)
{
cin >> rwoman[i] >> rman[i];
man[rman[i]] = i;
woman[rwoman[i]] = i;
addEdge(i + n, i);
}
cin >> m;
range(i, 1, m)
{
cin >> u >> v;
addEdge(woman[u], man[v]);
}
range(i, 1, 2 * n) if (dfn[i] == 0) tarjan(i);
range(i, 1, n) if (color_num[color[i]] == 1) puts("Safe");
else puts("Unsafe");
}
return 0;
}