BZOJ 2140 稳定婚姻 ——二分图

论二分图的可行边与必须边。

考虑用dinic增广之后的图,一些是必要的割边,一些是可行的割边。

我们首先求出一组可行的最大匹配,那么这些变都是可行的。

然后我们求一遍强连通分量。

如果 scc[u]!=scc[v] 并且在最大匹配中 那么它是必须的,否则就是可行的。

如果 scc[u]==scc[v] 并且不在最大匹配中 那么它是可行的。

题目中已经给出了一个最大匹配,只需要建图Tarjan即可。

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
 
map <string,int> ma,mb; 
string sa,sb;
int n,m,ta,tb;
#define maxn 100005
int h[maxn],to[maxn],ne[maxn],en=0,s=0,t;
 
void add(int a,int b)
{to[en]=b;ne[en]=h[a];h[a]=en++;}
 
int dfn[maxn],low[maxn],sta[maxn],top=0,idx,vcnt,bel[maxn],ins[maxn];
 
void tarjan(int o)
{
    dfn[o]=low[o]=++idx;
    sta[++top]=o;ins[o]=1;
    for (int i=h[o];i>=0;i=ne[i])
        if (!dfn[to[i]]) tarjan(to[i]),low[o]=min(low[o],low[to[i]]);
        else if (ins[to[i]]) low[o]=min(low[o],dfn[to[i]]);
    if (low[o]==dfn[o])
    {
        int x=-1;
        vcnt++;
        while (x!=o)
        {
            x=sta[top--];
            bel[x]=vcnt;
            ins[x]=0;
        }
    }
}
 
int main()
{
    memset(h,-1,sizeof h);
    scanf("%d",&n);
    t=2*n+1;
    F(i,1,n)
    {
        cin>>sa>>sb;
        ma[sa]=++ta,mb[sb]=++tb;
        add(i+n,i),add(i,s),add(t,i+n); 
    }
    scanf("%d",&m);
    F(i,1,m)
    {
        cin>>sa>>sb;
        int l=ma[sa],r=mb[sb]+n;
        add(l,r);
    }
    F(i,0,t) if (!dfn[i]) tarjan(i);
    F(i,1,n) if (bel[i]==bel[i+n]) printf("Unsafe
");
    else printf("Safe
");
}

  

原文地址:https://www.cnblogs.com/SfailSth/p/6646793.html