论二分图的可行边与必须边。
考虑用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 "); }