https://www.luogu.org/problemnew/show/P2296
题目很简单,但竟然没一遍A,基础不行啊...
做法很显然,反向建边看哪些点和终点连通,再看哪些点合法能被走,最后正向dfs一次就行
然而没一遍A,是因为bfs的时候vis和ok的处理有问题(看代码
应该在找到节点之后,立即对其进行处理。而不应该在弹出队列的时候对节点进行处理
一个教训吧
0.5h
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<iostream> using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 1e5 + 5; struct node { int to,next,cost; }e[maxn << 1],rev[maxn << 1]; int fir[maxn],alloc,r_fir[maxn],r_alloc; void adde(int u,int v) { e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; swap(u,v); rev[++r_alloc].next = r_fir[u]; r_fir[u] = r_alloc; rev[r_alloc].to = v; } bool ok[maxn],vis[maxn],con[maxn]; int n,m,s,t; void mark_rev() { queue<int> q; q.push(t); vis[t] = 1,ok[t] = 1; memset(vis,0,sizeof(vis)); while(q.size()) { int u = q.front(); q.pop(); for(int i = r_fir[u];i;i = rev[i].next) { int v = rev[i].to; if(vis[v]) continue; vis[v] = ok[v] = 1; q.push(v); } } for(int u = 1;u <= n;u++) { bool flag = 0; for(int i = fir[u];i;i = e[i].next) { int v = e[i].to; if(ok[v] == 0) { con[u] = 0; flag = 1; break; } } if(flag == 0) con[u] = 1; } } int dis[maxn]; void solve() { memset(vis,0,sizeof(vis)); queue<int> q; q.push(s); dis[s] = 0; vis[s] = 1; while(q.size()) { int u = q.front(); q.pop(); for(int i = fir[u];i;i = e[i].next) { int v = e[i].to; if(vis[v] || con[v] == 0) continue; dis[v] = dis[u] + 1; vis[v] = 1; q.push(v); } } if(dis[t] == 0) printf("-1"); else printf("%d",dis[t]); } int main() { n = read(),m = read(); for(int i = 1;i <= m;i++) { int u = read(),v = read(); if(u == v) continue; adde(u,v); } s = read(),t = read(); mark_rev(); solve(); }