P1407 [國家集訓隊] 穩定婚姻

Glowingfire發表於2024-11-29

[國家集訓隊] 穩定婚姻

題目描述

我們已知 \(n\) 對夫妻的婚姻狀況,稱第 \(i\) 對夫妻的男方為 \(B_i\),女方為 \(G_i\)。若某男 \(B_i\) 與某女 \(G_j\) 曾經交往過(無論是大學,高中,亦或是幼兒園階段,\(i \le j\)),則當某方與其配偶(即 \(B_i\)\(G_i\)\(B_j\)\(G_j\))感情出現問題時,他們有私奔的可能性。不妨設 \(B_i\) 和其配偶 \(G_i\) 感情不和,於是 \(B_i\)\(G_j\) 舊情復燃,進而 \(B_j\) 因被戴綠帽而感到不爽,聯絡上了他的初戀情人 \(G_k\) ……一串串的離婚事件像多米諾骨牌一般接踵而至。若在 \(B_i\)\(G_i\) 離婚的前提下,這 \(2n\) 個人最終依然能夠結合成 \(n\) 對情侶,那麼我們稱婚姻 \(i\) 為不安全的,否則婚姻 \(i\) 就是安全的。

給定所需資訊,你的任務是判斷每對婚姻是否安全。

輸入格式

第一行為一個正整數 \(n\),表示夫妻的對數;

以下 \(n\) 行,每行包含兩個字串,表示這 \(n\) 對夫妻的姓名(先女後男),由一個空格隔開;

\(n+2\) 行包含一個正整數 \(m\),表示曾經相互喜歡過的情侶對數;

以下 \(m\) 行,每行包含兩個字串,表示這 \(m\) 對相互喜歡過的情侶姓名(先女後男),由一個空格隔開。

輸出格式

輸出檔案共包含 \(n\) 行,第 \(i\) 行為 Safe(如果婚姻 \(i\) 是安全的)或 Unsafe(如果婚姻 \(i\) 是不安全的)。

樣例 #1

樣例輸入 #1

2
Melanie Ashley
Scarlett Charles
1
Scarlett Ashley

樣例輸出 #1

Safe
Safe

樣例 #2

樣例輸入 #2

2
Melanie Ashley
Scarlett Charles
2
Scarlett Ashley
Melanie Charles

樣例輸出 #2

Unsafe
Unsafe

提示

對於 \(20\%\) 的資料,\(n \le 20\)

對於 \(40\%\) 的資料,\(n \le 100\)\(m \le 400\)

對於 \(100\%\) 的資料,所有姓名字串中只包含英文大小寫字母,大小寫敏感,長度不大於 \(8\),保證每對關係只在輸入檔案中出現一次,輸入檔案的最後 \(m\) 行不會出現未在之前出現過的姓名,這 \(2n\) 個人的姓名各不相同,\(1 \le n \le 4000\)\(0 \le m \le 20000\)

分析

對於n對夫妻 $ (u,v) $ 和m對前情侶 $ (u',v') $ ,建邊 $ u->v $ 和 $ v'->u' $ 。

跑一邊Tarjan縮點,如果 $ (u,v) $ 在一個SCC中則不安全。因為此時 $ (u,v) $ 在長度大於3的偶環上,可以使得 $ (u,v') $ 和 $ (v,u') $ 配對。

如圖偏移一格

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+100,M=1e5+100;
int n,m;
int head[N],cnt;
int dfn[N],low[N],tot,dd;
int sta[N],top,id,scc[N];
int pa[N][2];
bool inc[N];
map<string,int>mp;
struct edge{int y,n;}e[M<<1];
string s1,s2;
void ad(int x,int y)
{
    e[++cnt].n=head[x];
    e[cnt].y=y;
    head[x]=cnt;
}

void go(int u)
{
    sta[++top]=u;
    inc[u]=1;
    low[u]=dfn[u]=++tot;
    for(int i=head[u];i;i=e[i].n)
    {
        int v=e[i].y;
        if(!dfn[v])
        {
            go(v);
            low[u]=min(low[u],low[v]);
        }
        else if(inc[v])
            low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u])
    {
        ++id;
        while(sta[top]!=u)
        {
            scc[sta[top]]=id;
            inc[sta[top]]=0;
            --top;
        }
        scc[u]=id;
        inc[u]=0;
        --top;
    }
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        cin>>s1>>s2;
        int id1=mp[s1],id2=mp[s2];
        if(!id1)id1=mp[s1]=++dd;
        if(!id2)id2=mp[s2]=++dd;
        pa[i][0]=id1;
        pa[i][1]=id2;
        ad(id1,id2);

    }
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    {
        cin>>s1>>s2;
        int x=mp[s2],y=mp[s1];
        ad(x,y);
    }
    for(int i=1;i<=dd;++i)
        if(!dfn[i])go(i);
    for(int i=1;i<=n;++i)
    {
        if(scc[pa[i][0]]==scc[pa[i][1]])printf("Unsafe");
        else printf("Safe");
        putchar('\n');
    }
    return 0;
}

相關文章