1. 程式人生 > >洛谷 P1407 [國家集訓隊]穩定婚姻 解題報告

洛谷 P1407 [國家集訓隊]穩定婚姻 解題報告

可能性 scanf ron 強聯通 tro std 合成 尋找 國家

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\)

和其配偶\(G_i\)感情不和,於是\(B_i\)\(G_j\)舊情復燃,進而Bj因被戴綠帽而感到不爽,聯系上了他的初戀情人\(G_k\)……一串串的離婚事件像多米諾骨牌一般接踵而至。若在\(B_i\)\(G_i\)離婚的前提下,這2\(n\)個人最終依然能夠結合成\(n\)對情侶,那麽我們稱婚姻i為不安全的,否則婚姻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 [國家集訓隊]穩定婚姻 解題報告