P14618 题解
copper_ingot · · 题解
题目传送门
简单图论题。
首先反向建边预处理出所有可以到达
之后对于每个点,选取从它连出的权值最小的边来走。如果走到了已经经过的点,说明走到了一个极小权值的环里,如果一直在这个环上走字典序就最小,此时序列为无限长。
如果序列是有限的,那么每个点最多经过一次,序列最长为
代码:
//copper_ingot
#include <bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
pii mkp(int x, int y){pii p; p.first = x, p.second = y; return p;}
int n, m, s, t, vis[200001], flag, a[200001], cnt;
vector<pii> g[200001], h[200001];
void dfs1(int u){
vis[u] = 1;
for (int i = 0; i < g[u].size(); i++)
if (!vis[g[u][i].second]) dfs1(g[u][i].second);
}
void dfs2(int u){
if (flag || u == t) return;
if (vis[u]){flag = 1; return;}
vis[u] = 1, a[++cnt] = h[u][0].first;
dfs2(h[u][0].second);
}
signed main(){
scanf("%d%d%d%d", &n, &m, &s, &t);
for (int i = 1; i <= m; i++){
int u, v, w; scanf("%d%d%d", &u, &v, &w);
g[v].push_back(mkp(w, u));
}
dfs1(t);
if (!vis[s]){puts("IMPOSSIBLE"); return 0;}
for (int u = 1; u <= n; u++){
if (!vis[u]) continue;
for (int i = 0; i < g[u].size(); i++){
int v = g[u][i].second, w = g[u][i].first;
if (!vis[v]) continue;
h[v].push_back(mkp(w, u));
}
}
for (int i = 1; i <= n; i++){sort(h[i].begin(), h[i].end()); vis[i] = 0;}
dfs2(s);
if (flag){puts("TOO LONG"); return 0;}
for (int i = 1; i <= cnt; i++) printf("%d ", a[i]);
return 0;
}