挑战最唐最神经做法!!1
哥们来写唐诗做法了!!1111
首先注意到转移肯定是:
初始
这里有一种优质做法,就是先把所有的值设为
但是本人太菜了,不会这一种做法,于是想出了一种唐诗做法。
考虑先跑一次 bfs,跑出转移的前半部分
接下来考虑
接下来考虑具体什么时候可以集体减一,不难发现若
那么不难发现,将图的强连通分量缩掉之后,若一个点没有出边,也就是没有被支配,那么就可以集体减一了。
接下来重复这个过程即可,每次跑 bfs,然后找能集体减一的块。
接下来口胡一下复杂度,注意到每次集体减一的块的
时间复杂度
const int N = 3e3 + 5;
const int M = 1e5 + 5;
const int INF = 1e9 + 7;
int n, m, st, ed;
vector<int> e[N], g[N];
int f[N], vis[N];
int fi[N], ne[M], to[M], ecnt;
int dfn[N], low[N], cnt;
int stk[N], tp;
int scc[N], sc;
int ru[N], b[N];
void add(int u, int v) {
ne[++ ecnt] = fi[u];
to[ecnt] = v;
fi[u] = ecnt;
}
void bfs() {
FOR(i, 1, n) vis[i] = 0;
deque<int> q;
q.push_back(ed);
while(! q.empty()) {
int u = q.front();
q.pop_front();
if(vis[u]) continue;
vis[u] = 1;
for(int v : e[u]) {
if(f[v] == f[u]) {
q.push_front(v);
}
if(f[v] >= f[u] + 1) {
f[v] = f[u] + 1;
q.push_back(v);
}
}
}
}
void clear() {
FOR(i, 1, n) fi[i] = dfn[i] = low[i] = vis[i] = 0;
ecnt = cnt = sc = tp = 0;
}
void tarjan(int u) {
dfn[u] = low[u] = ++ cnt;
stk[++ tp] = u;
vis[u] = 1;
for(int i = fi[u]; i; i = ne[i]) {
int v = to[i];
if(! dfn[v]) {
tarjan(v);
chmin(low[u], low[v]);
}
else if(vis[v]) {
chmin(low[u], dfn[v]);
}
}
if(dfn[u] == low[u]) {
sc ++;
while(1) {
scc[stk[tp]] = sc;
vis[stk[tp]] = 0;
tp --;
if(stk[tp + 1] == u) break;
}
}
}
void solve() {
cin >> n >> m;
REP(_, m) {
int u, v;
cin >> u >> v;
e[v].push_back(u);
g[u].push_back(v);
}
cin >> st >> ed;
FOR(i, 1, n) f[i] = INF;
f[ed] = 0;
while(1) {
bfs();
clear();
FOR(u, 1, n) {
int mx = 0; b[u] = 0;
for(int v : g[u]) chmax(mx, f[v]);
if(mx <= f[u]) {
for(int v : g[u])
if(f[v] == f[u]) add(u, v);
}
else {
b[u] = 1;
}
}
bool ok = 0;
FOR(u, 1, n) if(! dfn[u]) tarjan(u);
FOR(i, 1, sc) ru[i] = 0;
FOR(u, 1, n) for(int i = fi[u]; i; i = ne[i]) {
int v = to[i];
if(scc[u] != scc[v]) ru[scc[u]] ++;
}
FOR(u, 1, n) if(f[u] != INF && scc[u] != scc[ed] && ! ru[scc[u]] && ! b[u]) f[u] --, ok = 1;
if(! ok) break;
}
cout << (f[st] == INF ? - 1 : f[st]);
}