洛谷 P1407 [國家集訓隊]穩定婚姻 解題報告
P1407 [國家集訓隊]穩定婚姻
題目描述
我國的離婚率連續7年上升,今年的頭兩季,平均每天有近5000對夫婦離婚,大城市的離婚率上升最快,有研究婚姻問題的專家認為,是與簡化離婚手續有關。
25歲的姍姍和男友談戀愛半年就結婚,結婚不到兩個月就離婚,是典型的“閃婚閃離”例子,而離婚的導火線是兩個人爭玩電腦遊戲,丈夫一氣之下,把電腦炸爛。
有社會工作者就表示,80後求助個案越來越多,有些是與父母過多幹預有關。而根據民政部的統計,中國離婚五大城市首位是北京,其次是上海、深圳,廣州和廈門,那麽到底是什麽原因導致我國成為離婚大國呢?有專家分析說,中國經濟急速發展,加上女性越來越來越獨立,另外,近年來簡化離婚手續是其中一大原因。
——以上內容摘自第一視頻門戶
現代生活給人們施加的壓力越來越大,離婚率的不斷升高已成為現代社會的一大問題。而其中有許許多多的個案是由婚姻中的“不安定因素”引起的。妻子與丈夫吵架後,心如絞痛,於是尋求前男友的安慰,進而夫妻矛盾激化,最終以離婚收場,類似上述的案例數不勝數。
我們已知\(n\)對夫妻的婚姻狀況,稱第i對夫妻的男方為\(B_i\),女方為\(G_i\)。若某男\(B_i\)與某女\(G_j\)曾經交往過(無論是大學,高中,亦或是幼兒園階段,\(i≠j\)),則當某方與其配偶(即\(B_i\)與\(G_i\)或\(B_j\)與\(G_j\))感情出現問題時,他們有私奔的可能性。不妨設\(B_i\)
給定所需信息,你的任務是判斷每對婚姻是否安全。
輸入輸出格式
輸入格式:
第一行為一個正整數\(n\),表示夫妻的對數;
以下\(n\)行,每行包含兩個字符串,表示這\(n\)對夫妻的姓名(先女後男),由一個空格隔開;
第\(n+2\)行包含一個正整數\(m\)
以下\(m\)行,每行包含兩個字符串,表示這\(m\)對相互喜歡過的情侶姓名(先女後男),由一個空格隔開。
輸出格式:
輸出文件共包含\(n\)行,第i行為“\(Safe\)”(如果婚姻i是安全的)或“\(Unsafe\)”(如果婚姻i是不安全的)。
說明
對於20%的數據,\(n\)≤20;
對於40%的數據,\(n\)≤100,\(m\)≤400;
對於100%的數據,所有姓名字符串中只包含英文大小寫字母,大小寫敏感,長度不大於8,保證每對關系只在輸入文件中出現一次,輸入文件的最後m行不會出現未在之前出現過的姓名,這2n個人的姓名各不相同,1≤\(n\)≤4000,0≤\(m\)≤20000。
最初我的做法是所有邊連成無向邊跑割邊,如果夫妻線是割邊則代表是安全的,反之不是。可以先別往下劃,想想為什麽這個想法是錯誤的。
下面進入正題,很容易想到一種暴力算法,枚舉斷掉的夫妻邊跑二分圖匹配,復雜度\(O(n^2m)\),期望得分40~50分,實際得分不知道。
暴力算法一般都能帶給我們一個思考方向或者啟示,這題也不例外。
我們將原本連上夫妻邊的一個圖看做是一個已經完成匹配的模型,當匹配邊\(e\)斷掉後,\(e\)所連接的兩個點就斷開了,為了保證匹配數不減小,我們跑假使開始跑二分圖匹配,因為所有的點都是匹配好的,所以當某一對點失去配對後,一定要去NTR別人,這時候即是一個對邊反悔的時機,也就是尋找增廣路徑。我們將夫妻關系由女向男連上一條有向邊表示可能反悔。而情侶關系則表示原本的正邊由男連女的有向邊。
繼續想,當斷掉\(E(u,v)\)後,我們從\(u\)開始尋找增廣路,因為我們不能失去任何一個配對所以增廣路的末尾一個一定是\(v\),也就是說,如果能跑到\(v\),那麽\(E(u,v)\)這條邊一定在一個環上。
由此,問題轉為了有向圖求強聯通分量。
到這裏,跑割邊的錯誤也就非常明顯了。
code:
#include <cstdio>
#include <iostream>
#include <map>
using namespace std;
const int N=8010;
const int M=20010;
int m,n=0;
string c1,c2;
map <string,int > ma;
struct Edge
{
int to,next;
}edge[(M<<1)+N];
int head[N],cnt=1,is[(M<<1)+N];
void add(int u,int v)
{
edge[++cnt].next=head[u];edge[cnt].to=v;head[u]=cnt;
}
int time=0,low[N],dfn[N],s[N],tot=0,ha[N],in[N],n0=0;
void push(int x){s[++tot]=x;}
void pop(){tot--;}
void tarjan(int now)
{
dfn[now]=low[now]=++time;
in[now]=1;
push(now);
for(int i=head[now];i;i=edge[i].next)
{
int v=edge[i].to;
if(!dfn[v])
{
tarjan(v);
low[now]=min(low[now],low[v]);
}
else if(in[v])
low[now]=min(low[now],dfn[v]);
}
if(dfn[now]==low[now])
{
n0++;int k;
do
{
k=s[tot];
pop();
ha[k]=n0;
in[k]=0;
}while(k!=now);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>c1>>c2;
ma[c1]=i,ma[c2]=n+i;
add(i,n+i);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
cin>>c1>>c2;
add(ma[c2],ma[c1]);
}
for(int i=1;i<=n<<1;i++)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;i++)
if(ha[i]==ha[i+n])
printf("Unsafe\n");
else
printf("Safe\n");
return 0;
}
2018.6.10
洛谷 P1407 [國家集訓隊]穩定婚姻 解題報告