题目:
我们已知n对夫妻的婚姻状况,称第i对夫妻的男方为Bi,女方为Gi。若某男Bi与某女Gj曾经交往过(无论是大学,高中,亦或是幼儿园阶段,i≠j),则当某方与其配偶(即Bi与Gi或Bj与Gj)感情出现问题时,他们有私奔的可能性。不妨设Bi和其配偶Gi感情不和,于是Bi和Gj旧情复燃,进而Bj因被戴绿帽而感到不爽,联系上了他的初恋情人Gk……一串串的离婚事件像多米诺骨牌一般接踵而至。若在Bi和Gi离婚的前提下,这2n个人最终依然能够结合成n对情侣,那么我们称婚姻i为不安全的,否则婚姻i就是安全的。给定所需信息,你的任务是判断每对婚姻是否安全。
输入:
第一行为一个正整数n,表示夫妻的对数;
以下n行,每行包含两个字符串,表示这n对夫妻的姓名(先女后男),由一个空格隔开;
第n+2行包含一个正整数m,表示曾经相互喜欢过的情侣对数;
以下m行,每行包含两个字符串,表示这m对相互喜欢过的情侣姓名(先女后男),由一个空格隔开。
所有姓名字符串中只包含英文大小写字母,大小写敏感,长度不大于8,
保证每对关系只在输入文件中出现一次,输入文件的最后m行不会出现未在之前出现过的姓名,
这2n个人的姓名各不相同
输出:
输出文件共包含n行,第i行为“Safe”(如果婚姻i是安全的)或“Unsafe”(如果婚姻i是不安全的)。
数据范围:
对于 15% 的数据: 2 <= n <= 20,2 <= m <= 40
对于 40% 的数据: 2 <= n <= 100,2 <= m <= 400
对于 60% 的数据: 2 <= n <= 3500,2 <= m <= 10000
对于 100% 的数据:2 <= n <= 4000 2 <= m <= 20000
所有姓名字符串中只包含英文大小写字母,大小写敏感,长度不大于8
输入样例:
样例输入1:
2
Melanie Ashley
Scarlett Charles
1
Scarlett Ashley
样例输入2:
2
Melanie Ashley
Scarlett Charles
2
Scarlett Ashley
Melanie Charles
样例输入3:
3
Alice Apple
Bob Banana
Celina Cat
2
Alice Banana
Bob Apple
输出样例:
样例输出1:
Safe
Safe
样例输出2:
Unsafe
Unsafe
样例输出3:
Unsafe
Unsafe
Safe
思路:
由题目可看出,这是个二分图,正式的夫妻女向男连边,旧情人男向女连边,如果夫妻二人在同一个强连通分量内,那么找到夫妻男到女的一个环,关系在环上转移一下就离婚了,因此只需要求强连通分量即可。
代码:
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
#define met(a) memset(a,0,sizeof(a))
using namespace std;
const int mod=1e9+7;
const int N = 4010;
const int MAXN = 10020;
const int MAXM = 50020;
char a[10] , b[10];
struct Edge{
int to , next;
}edge[MAXM];
int head[MAXN] , tot;
int Low[MAXN],DFN[MAXN],Stack[MAXN],Belong[MAXN];
int Index , top;
int scc;
bool Instack[MAXN];
int name[MAXN*2];
int num[MAXN];
int sd = 0;
map<string , int> mp;
void addedge(int u , int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void Tarjan(int u)
{
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for(int i = head[u] ; i != -1 ; i= edge[i].next)
{
v = edge[i].to;
if(!DFN[v])
{
Tarjan(v);
if(Low[u] > Low[v])
{
Low[u] = Low[v];
}
}
else if(Instack[v] && Low[u] > DFN[v])
{
Low[u] = DFN[v];
}
}
if(Low[u] == DFN[u])
{
scc++;
do{
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
num[scc]++;
}
while(v!=u);
}
}
void solve(int N)
{
memset(DFN , 0 , sizeof(DFN));
memset(Instack , false , sizeof(Instack));
memset(num , 0 , sizeof(num));
Index = scc = top = 0;
for(int i = 1 ; i <= N ; i++)
{
if(!DFN[i])
{
Tarjan(i);
// num[i] = scc;
// scc = 0;
}
}
}
void init()
{
tot = 0;
memset(head , -1 , sizeof(head));
}
int main()
{
int n;
cin >> n;
tot = 0;
init();
for(int i = 1 ; i <= n ; i++)
{
scanf("%s %s",a,b);
if(!mp[a])
mp[a] = ++sd;
if(!mp[b])
mp[b] = ++sd;
int xx = mp[a];
int yy = mp[b];
name[2*i-1] = xx;
name[2*i] = yy;
addedge(xx,yy);
}
int m;
cin >> m;
for(int i = 1 ; i <= m ; i++)
{
scanf("%s %s",a,b);
// edge[mp[b]].to = mp[a];
// edge[mp[a]].next = mp[b];
int xx = mp[a];
int yy = mp[b];
addedge(yy,xx);
}
// for(int i = 0 ; i < tot ; ++i)
// {
// init();
// if(!DFN[i])
// {
// Tarjan(i);
// num[i] = scc;
// scc = 0;
// }
// }
for(int i=1;i<=sd;i++){
if(!DFN[i]) Tarjan(i);
}
for(int i = 1 ; i <= n ; ++i)
{
if(Low[name[2*i-1]] == Low[name[i*2]] )
cout << "Unsafe" << endl;
else
cout << "Safe" << endl;
}
return 0;
}