BZOJ2140: 稳定婚姻(洛谷P1407)

版权声明:蒟蒻Blog随意转载 https://blog.csdn.net/a1799342217/article/details/82843887

Tarjan

洛谷题目传送门
BZOJ题目传送门

一个unsafe的情况就是把当前边拆掉后仍然有增广路。

我们把原来夫妻的边由女方连到男方,旧情的边由男方连到女方。这样也是一个二分图,但是可能出现环。把这些环缩起来,可以证明如果夫妻都在一个强连通分量里就是unsafe的。因为如果在环上断了一条边,由于是偶环,一定能够重新构建出来一个匹配。而不在一个强连通分量则说明他们之间一定有条匹配的边是不能被调整的。

代码:

#include<map>
#include<cctype>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#define N 8005
#define M 20005
using namespace std;
struct edge{ int nxt,to; }ed[M<<1];
int n,m,k,tp,p,h[N],num[N],dfn[N],low[N],stk[N];
map <string,int> mp; char s1[10],s2[10]; bool f[N];
#define add(x,y) ed[++k]=(edge){h[x],y},h[x]=k
void Tarjan(int x){
	low[x]=dfn[x]=++p,stk[++tp]=x,f[x]=true;
	for (int i=h[x],v;i;i=ed[i].nxt)
		if (!dfn[v=ed[i].to]) Tarjan(v),low[x]=min(low[x],low[v]);
		else if (f[v]) low[x]=min(low[x],dfn[v]);
	if (dfn[x]==low[x]){
		while (stk[tp]!=x) num[stk[tp]]=x,f[stk[tp--]]=false;
		tp--,num[x]=x,f[x]=false;
	}
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%s%s",s1,s2),mp[s1]=i,mp[s2]=i+n,add(i,i+n);
	scanf("%d",&m);
	for (int i=1;i<=m;i++)
		scanf("%s%s",s1,s2),add(mp[s2],mp[s1]);
	for (int i=1;i<=n;i++) if (!dfn[i]) Tarjan(i);
	for (int i=1;i<=n;i++) puts(num[i]==num[i+n]?"Unsafe":"Safe");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1799342217/article/details/82843887