[洛谷P1407][国家集训队]稳定婚姻

题目大意:有$n$对夫妻和$m$对情人,如果一对情人中的两人都离婚了,那么他们可以结为夫妻。对于每一对夫妻,若他们离婚后所有人依然可以结婚,那么就是不安全的,否则是安全的。问每一对夫妻是否安全。

题解:考虑$tarjan$缩点。把图转成有向图,夫妻之间$G->B$,情人之间$B->G$,$tarjan$缩点,最后判断每一对夫妻是否在同一个强连通分量内($size>1$),如果在就是不安全(连成了一个环),反之安全。

卡点:1.$tarjan$中当$DFN_v$访问过时,未判断$v$是否在$stack$内



C++ Code:

#include <cstdio>
#include <iostream>
#include <map>
#define PIS pair<int, string>
#define MP make_pair
#define maxn 8010
#define maxm 40010
using namespace std;
map<string, int> name;
int n, nn, m, name_idx;
string name_p[maxn];

int head[maxn], cnt;
struct Edge {
	int to, nxt;
} e[maxm << 1];
void add(int a, int b) {
	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
}

int DFN[maxn], low[maxn], stack[maxn], tot, idx;
int res[maxn], res_idx, sz[maxn];
bool ins[maxn];
inline int min(int a, int b) {return a < b ? a : b;}
void tarjan(int u) {
	int v;
	DFN[u] = low[u] = ++idx;
	ins[stack[++tot] = u] = true;
	for (int i = head[u]; i; i = e[i].nxt) {
		v = e[i].to;
		if (!DFN[v]) {
			tarjan(v);
			low[u] = min(low[u], low[v]);
		} else if (ins[v]) low[u] = min(low[u], DFN[v]);
	}
	if (DFN[u] == low[u]) {
		res_idx++;
		int siz = 0;
		do {
			ins[v = stack[tot--]] = false;
			res[v] = res_idx; siz++;
		} while (v != u);
		sz[res_idx] = siz;
	}
}

int main() {
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
	cin >> n; nn = n << 1;
	for (int i = 0; i < n; i++) {
		string a, b;
		cin >> a >> b;
		name_p[++idx] = a;
		name.insert(MP(a, idx));
		name_p[++idx] = b;
		name.insert(MP(b, idx));
		add(idx - 1, idx);
	}
	cin >> m;
	for (int i = 0; i < m; i++) {
		string a, b;
		cin >> a >> b;
		add(name[b], name[a]);
	}
	for (int i = 1; i <= nn; i++) {
		if (!DFN[i]) tarjan(i);
	}
	for (int i = 1; i <= n; i++) {
		if (sz[res[i << 1]] > 1) puts("Unsafe");
		else puts("Safe");
	}
	return 0;
}

 

posted @ 2018-08-23 19:06  Memory_of_winter  阅读(171)  评论(0编辑  收藏  举报