• 【tarjan】BZOJ2140-稳定婚姻


    又名NTR的故事

    【题目大意】

    n对夫妻Bi和Gi。若某男Bi与某女Gj曾经交往过,他们有私奔的可能性。不妨设Bi和Gj旧情复燃,进而Bj会联系上了他的初恋情人Gk,以此递推。若在Bi和Gi离婚的前提下,这2n个人最终依然能够结合成n对情侣,那么我们称婚姻i为不安全的,否则婚姻i就是安全的。问n对夫妻的婚姻分别是安全的吗?

    【思路】

    第一反应是匈牙利算法,但是太过于暴力了,过不了。

    我们把夫妻中女方连向男方,旧情中男方连向女方。可以得出结论:如果该有向图的强连通分量中,夫妻双方在同一个强连通分量里,那么他们的婚姻是不安全的,否则他们的婚姻是安全的。

    为什么呢?如果在同一个强连通分量中,显然可以连出一个增广路,相当于匈牙利算法可以跑,那么必定是能形成新的n对情侣的。

    如果不在一个强连通分量中,可以理解为匈牙利算法不能调整了(具体原因见匈牙利算法),那么必定不能形成新的n对情侣。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<map>
     6 #include<vector>
     7 #include<stack>
     8 using namespace std;
     9 map<string,int> Name;
    10 const int MAXN=4000+50;
    11 int n,m;
    12 int cnt,col,dfn[MAXN*2],low[MAXN*2],instack[MAXN*2],tar[MAXN*2];
    13 vector<int> E[MAXN*2];
    14 stack<int> S;
    15 
    16 void addedge(int u,int v){E[u].push_back(v);}
    17 
    18 void tarjan(int u)
    19 {
    20     low[u]=dfn[u]=++cnt;
    21     S.push(u);
    22     instack[u]=1;//不要忘记了这两句
    23     for (int i=0;i<E[u].size();i++)
    24     {
    25         int v=E[u][i];
    26         if (!instack[v])
    27         {
    28             tarjan(v);
    29             low[u]=min(low[u],low[v]);
    30         }
    31         else if (instack[v]==1) low[u]=min(low[u],dfn[v]);
    32     }
    33     
    34     if (low[u]==dfn[u])
    35     {
    36         ++col;
    37         while (S.top()!=u)
    38         {
    39             tar[S.top()]=col,instack[S.top()]=2;
    40             S.pop();
    41         }
    42         tar[u]=col,instack[u]=2;
    43         S.pop();
    44     }
    45 }
    46 
    47 void init()
    48 {
    49     scanf("%d",&n);
    50     for (int i=1;i<=n;i++)
    51     {
    52         char wife[15],husband[15];
    53         scanf("%s%s",wife,husband);
    54         Name[wife]=i;
    55         Name[husband]=i+n;
    56         addedge(i,i+n);
    57     }
    58     scanf("%d",&m);
    59     for (int i=1;i<=m;i++)
    60     {
    61         char Exgf[15],Exbf[15];
    62         scanf("%s%s",Exgf,Exbf);
    63         int exgf=Name[Exgf],exbf=Name[Exbf];
    64         addedge(exbf,exgf);
    65     }
    66 }
    67 
    68 void solve()
    69 {
    70     cnt=col=0;
    71     while (!S.empty()) S.pop();
    72     memset(instack,0,sizeof(instack));
    73     for (int j=1;j<=2*n;j++) if (!instack[j]) tarjan(j);
    74     for (int i=1;i<=n;i++)
    75         if (tar[i]==tar[i+n]) puts("Unsafe");
    76             else puts("Safe");
    77 }
    78 
    79 int main()
    80 {
    81     init();
    82     solve();
    83     return 0;
    84 }
  • 相关阅读:
    git-【六】分支的创建与合并
    git-【五】远程仓库
    git-【四】撤销修改和删除文件操作
    git-【三】理解工作区与暂存区的区别
    git-【二】本地git操作提交、版本回退
    git-【一】概述安装
    java-基础-【四】实际编程中的对象
    博客园打赏、赞助功能
    js-template-art【四】通过helper方法注册,调用外部方法
    js-template-art【三】js api
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5876168.html
Copyright © 2020-2023  润新知