题意
题解
求原图中的各条匹配边是否是最大匹配的必经边。那么枚举匹配边 ( u , v ) (u,v) (u,v),将其删除后(匈牙利算法中匹配边可以通过点的匹配信息找到,故匹配边可以不用显式地添加到图中,此时也避免了删边操作),设 u , v u,v u,v 为未匹配状态,若从 u u u 出发能找到一条增广路,则这条匹配边不是最大匹配的必经边,将其删除后仍能找到图中一组完备匹配。
总时间复杂度 O ( n m ) O(nm) O(nm)。
#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int MAXN = 8e5 + 5;
int N, M;
map<string, int> idx;
int match[MAXN];
vector<int> G[MAXN];
bool res[MAXN], used[MAXN];
void add_edge(int u, int v)
{
G[u].pb(v), G[v].pb(u);
}
bool dfs(int u)
{
used[u] = 1;
for (int v : G[u])
{
int w = match[v];
if (w == -1 || (!used[w] && dfs(w)))
{
return 1;
}
}
return 0;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> N;
for (int i = 0; i < N; ++i)
{
string u, v;
cin >> u >> v;
idx[u] = i, idx[v] = N + i;
match[i] = i + N, match[N + i] = i;
}
cin >> M;
for (int i = 0; i < M; ++i)
{
string u, v;
cin >> u >> v;
add_edge(idx[u], idx[v]);
}
for (int i = 0; i < N; ++i)
{
match[i] = match[N + i] = -1;
memset(used, 0, sizeof(used));
if (dfs(i))
res[i] = 1;
match[i] = N + i, match[N + i] = i;
}
for (int i = 0; i < N; ++i)
cout << (res[i] ? "Unsafe" : "Safe") << '\n';
return 0;
}