14

[国家集训队]稳定婚姻 题解

 3 years ago
source link: http://www.cnblogs.com/C202202chenkelin/p/14014806.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

题目描述

我国的离婚率连续7年上升,今年的头两季,平均每天有近5000对夫妇离婚,大城市的离婚率上升最快,有研究婚姻问题的专家认为,是与简化离婚手续有关。

25岁的姗姗和男友谈恋爱半年就结婚,结婚不到两个月就离婚,是典型的“闪婚闪离”例子,而离婚的导火线是两个人争玩电脑游戏,丈夫一气之下,把电脑炸烂。

有社会工作者就表示,80后求助个案越来越多,有些是与父母过多干预有关。而根据民政部的统计,中国离婚五大城市首位是北京,其次是上海、深圳,广州和厦门,那么到底是什么原因导致我国成为离婚大国呢?有专家分析说,中国经济急速发展,加上女性越来越来越独立,另外,近年来简化离婚手续是其中一大原因。

——以上内容摘自第一视频门户

现代生活给人们施加的压力越来越大,离婚率的不断升高已成为现代社会的一大问题。而其中有许许多多的个案是由婚姻中的“不安定因素”引起的。妻子与丈夫吵架后,心如绞痛,于是寻求前男友的安慰,进而夫妻矛盾激化,最终以离婚收场,类似上述的案例数不胜数。

我们已知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对相互喜欢过的情侣姓名(先女后男),由一个空格隔开。

输出格式

输出文件共包含n行,第i行为“Safe”(如果婚姻i是安全的)或“Unsafe”(如果婚姻i是不安全的)。

输入输出样例

输入 #1

2
Melanie Ashley
Scarlett Charles
1
Scarlett Ashley

输出 #1

Safe
Safe

输入 #2

2
Melanie Ashley
Scarlett Charles
2
Scarlett Ashley
Melanie Charles

输出 #2

Unsafe
Unsafe

说明/提示

对于20%的数据,n≤20;

对于40%的数据,n≤100,m≤400;

对于100%的数据,所有姓名字符串中只包含英文大小写字母,大小写敏感,长度不大于8,保证每对关系只在输入文件中出现一次,输入文件的最后m行不会出现未在之前出现过的姓名,这2n个人的姓名各不相同,1≤n≤4000,0≤m≤20000。

分析

我承认,是这新颖的题面吸引了我。( 幼儿园阶段??旧情复燃??

就拿样例二来举例子(Melanie为1,Ashley为2,Melanie为3,Charles为4)

关系如图所示

eYZ7be6.png!mobile

(解释:1和2,3和4是夫妻关系,1和4,2和3是前恋人)

若1,2发生争吵,则2和3会旧情复燃,则4看了就很不爽,和1旧情复燃。

则原关系(1,2)和(3,4)会打乱关系成(1,4)和(2,3)。且不会有其他人参与。

从上述跑一遍样例的过程中,不难发现1,2,3,4所成了一个环,这个环内就会发成置换夫妻。那么这个环内的所有所有元素都会变成不安全的婚姻。

可以想到用Tarjan算法找到所有的环。但是如何建图?若使用双向边来建图,是肯定不行的,因为只要是双向边所到之处,全都是环。

继续观察上图

发现:一对夫妻,假设发生争吵之后,女方先出轨,则必会找到另一个男人(他不好,我跟别人好),则找到的那个男人会和他的老婆发生争吵,则他的老婆会出轨。若是男方先出轨,则必会找到另一个女人,则找到的那个女人会和他的老公发生争吵,则她的老公会出轨。

如下图所示

u2a6Vzn.png!mobile

所以,夫妻之间是从男人到女人之间连边,恋人之间是从女人到男人之间连边。(或是夫妻之间从女人到男人之间连边,恋人之间从男人到女人之间连边,交换一下,也行)

连了边之后在跑一遍Tarjan,看是否自己独立是一个集合,若自己是独立集合,就说明这段婚姻是安全的。反之,不安全。

C++代码

#include <map>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
#define Min(a, b) ((a) < (b) ? (a) : (b))
void Quick_Read(int &N) {
	N = 0;
	char c = getchar();
	int op = 1;
	while(c < '0' || c > '9') {
		if(c == '-')
			op = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		N = (N << 1) + (N << 3) + c - 48;
		c = getchar();
	}
	N *= op;
}
struct Node {
	string Man_Name, Wife_Name;
	void Relat() {
		cin >> Man_Name;
		cin >> Wife_Name;
	}
};
struct Spouse {
	int Man_Number, Wife_Number;
};
const int MAXN = 1e5 + 5;
vector<int> v[MAXN];
map<string, int> real;
map<string, bool> Appear;
Spouse Mar[MAXN], Lov[MAXN];
bool safe[MAXN];
int n, m, peo;
stack<int> s;
int dfn[MAXN], low[MAXN], belong[MAXN], stnm[MAXN];
bool instack[MAXN];
int tim, cnt;
void Tarjan(int now) {
	dfn[now] = low[now] = ++tim;
	s.push(now);
	instack[now] = true;
	int SIZ = v[now].size();
	for(int i = 0; i < SIZ; i++) {
		int next = v[now][i];
		if(!dfn[next]) {
			Tarjan(next);
			low[now] = Min(low[now], low[next]);
		}
		else if(instack[next])
			low[now] = Min(low[now], dfn[next]); 
	}
	if(low[now] == dfn[now]) {
		cnt++;
		int Top = -1;
		while(Top != now) {
			Top = s.top(); s.pop();
			instack[Top] = false;
			belong[Top] = cnt;
			stnm[cnt]++;
		}
	}
}
void Build() {
	for(int i = 1; i <= peo; i++)
		if(!dfn[i])
			Tarjan(i);
	for(int i = 1; i <= peo; i++)
		if(stnm[belong[i]] <= 1)
			safe[i] = true;
	for(int i = 1; i <= n; i++) {
		bool flag = safe[Mar[i].Man_Number] & safe[Mar[i].Wife_Number];
		if(flag)
			printf("Safe\n");
		else
			printf("Unsafe\n");
	}
}
void Read() {
	Node Ipt;
	Quick_Read(n);
	for(int i = 1; i <= n; i++) {
		Ipt.Relat();
		if(!Appear[Ipt.Man_Name]) {
			Appear[Ipt.Man_Name] = true;
			real[Ipt.Man_Name] = ++peo;
		}
		if(!Appear[Ipt.Wife_Name]) {
			Appear[Ipt.Wife_Name] = true;
			real[Ipt.Wife_Name] = ++peo;
		}
		Mar[i].Man_Number = real[Ipt.Man_Name];
		Mar[i].Wife_Number = real[Ipt.Wife_Name];
		v[Mar[i].Wife_Number].push_back(Mar[i].Man_Number);
	}
	Quick_Read(m);
	for(int i = 1; i <= m; i++) {
		Ipt.Relat();
		if(!Appear[Ipt.Man_Name]) {
			Appear[Ipt.Man_Name] = true;
			real[Ipt.Man_Name] = ++peo;
		}
		if(!Appear[Ipt.Wife_Name]) {
			Appear[Ipt.Wife_Name] = true;
			real[Ipt.Wife_Name] = ++peo;
		}
		Lov[i].Man_Number = real[Ipt.Man_Name];
		Lov[i].Wife_Number = real[Ipt.Wife_Name];
		v[Lov[i].Man_Number].push_back(Lov[i].Wife_Number);
	}
}
int main() {
	Read();
	Build();
	return 0;
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK