这题很容易想到一个做法,缩点以后去掉重边,看看是不是一条链。
但是我这样打以后TLE了,因为边去重太慢了,所以我就改成拓扑,如果一次入队的点数超过了1,就不满足条件。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
const int N = 1010, M = 6010;
int n, m;
int tot, Head[N], ver[M], Next[M];
int tp, sta[N], id, dfn[N], low[N], cnt, dcc[N];
int in[N]; bool ins[N];
vector<int> a[N];
void add(int x, int y) {
tot++;
ver[tot] = y;
Next[tot] = Head[x];
Head[x] = tot;
}
void v_add(int x, int y) {
a[x].push_back(y);
}
void Tarjan(int x) {
sta[++tp] = x;
dfn[x] = low[x] = ++id;
ins[x] = 1;
for (int i = Head[x]; i; i = Next[i]) {
int y = ver[i];
if (!dfn[y]) Tarjan(y), low[x] = min(low[x], low[y]);
else if (ins[y]) low[x] = min(low[x], dfn[y]);
}
if (low[x] == dfn[x]) {
cnt++; int y;
do {
y = sta[tp--];
dcc[y] = cnt;
ins[y] = 0;
} while (x != y);
}
}
int main() {
int T; cin >> T;
while (T--) {
tot = 0, memset(Head, 0, sizeof(Head));
id = 0, memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
for (int i = 1; i <= cnt; i++) a[i].clear();
cnt = 0; memset(dcc, 0, sizeof(dcc));
memset(in, 0, sizeof(in));
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
}
for (int i = 1; i <= n; i++)
if (!dfn[i]) Tarjan(i);
for (int x = 1; x <= n; x++)
for (int i = Head[x]; i; i = Next[i]) {
int y = ver[i];
if (dcc[x] == dcc[y]) continue;
in[dcc[y]]++; v_add(dcc[x], dcc[y]);
}
queue<int> q;
for (int i = 1; i <= cnt; i++)
if (!in[i]) q.push(i);
bool bk = 1;
while (q.size()) {
int x = q.front(); q.pop();
if (q.size() > 0) { bk = 0; break; }
for (int i = 0; i < a[x].size(); i++) {
int y = a[x][i];
if (!--in[y]) q.push(y);
}
}
puts(bk ? "Yes" : "No");
}
return 0;
}
应该不是一条链吧, 假设缩点之后变成了这样的拓扑图
但是代码肯定是没有问题的