题目大意:给一个有向图,无多重边和自环,问能否至多去掉一条边,使这个图变为无环图。
先拓扑排序得到所有环上的结点。在这些结点中,选择入度为1的结点,尝试去掉指向它的边,看是否还有环;若无环,则符合题目要求。
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 500 + 10;
int n, m;
vector<int> G[MAX_N];
int degree[MAX_N], tmp[MAX_N];
int check(int v) {
int counts = 0;
queue<int> que;
que.push(v);
for (int u = 1; u <= n; u++) {
tmp[u] = degree[u];
}
while (!que.empty()) {
int u = que.front(); que.pop();
counts++;
for (int i = 0; i < G[u].size(); i++) {
int w = G[u][i];
// the edge to v is removed
if (w == v) continue;
tmp[w]--;
if (tmp[w] == 0) que.push(w);
}
}
return counts;
}
void solve() {
memset(degree, 0, sizeof(degree));
for (int v = 1; v <= n; v++) {
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i];
degree[u]++;
}
}
queue<int> que;
vector<int> topo;
for (int v = 1; v <= n; v++) {
if (degree[v] == 0) {
que.push(v);
}
}
while (!que.empty()) {
int v = que.front(); que.pop();
topo.push_back(v);
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i];
degree[u]--;
if (degree[u] == 0) que.push(u);
}
}
if (topo.size() == n) {
printf("YES\n");
return;
}
// find degree[v] = 1
for (int v = 1; v <= n; v++) {
if (degree[v] == 1) {
int k = check(v);
if (topo.size() + k == n) {
printf("YES\n");
return;
}
}
}
printf("NO\n");
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d %d", &u, &v);
G[u].push_back(v);
}
solve();
return 0;
}