版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/violinlove/article/details/81706480
已经开始上课了,心情总是不平静的,无论是作业还是竞赛,还差好大一截
这道题是图论题,我首先想建反向图 + Tarjan缩点 + 跑dfs标记可到达的点且搜到起点便停止 + 更新不可到达的点 + Spfa
然后 华丽丽的 WA
首先 Tarjan 缩点便是想错了(至此还没有掌握 图论 的套路,决定去刷套题了 ) 会将 路径长度 缩短
搜到 起点停止 -> 没有道理
更新点时 没想到 后效性 问题 ( 更深入的问题 )
正确做法:
建反向图 + 找到所有可到达的点 & 标记 + 对于一开始 就 不可到达的点 更新 原先可到达的点标记为不可遍历到( 注意后效性 ) + Spfa 跑一遍最短路(对于不可到达的点 跳过 即可 )
至于后效性,只是粗浅的理解了一下,此处____________挖个坑!!
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define inf 0x3f3f3f3f
using namespace std;
inline int wread(){
char c(getchar ());int wans (0),flag(1);
while (c<'0' ||c>'9'){if (c=='-') flag=-1; c=getchar ();}
while (c>='0' && c<='9'){wans=wans*10+c-'0';c=getchar ();}
return wans*=flag;
}
int n,m;
int K,hed[10005];
struct node{int u,v,nxt;}e[200008];
void ad (int u,int v){e[++K]=(node){u,v,hed[u]};hed[u]=K;}
int S_1,T_1;
bool vis[10005];
void dfs (int x){
if(vis[x]) return ;
vis[x]=true;
for (int i(hed[x]);i;i=e[i].nxt){
int v(e[i].v);
dfs(v);
}
}
int dis[10005], que[1000005];
bool inss[10005],ta[10005];
int main (){
n=wread(),m=wread();
for (int i(1);i<=m;++i){
int u(wread()),v(wread());
if (u==v) continue;
ad(v,u);
}
S_1=wread(),T_1=wread();
// 标记
dfs(T_1);
//更新 不可遍历
vis[S_1]=vis[T_1]=1;
memcpy(ta,vis,sizeof ta);//拷贝一份,避免后效性
for (int i(1);i<=n;++i){
if (i==S_1 || i==T_1 ) continue;
if (ta[i]) continue;
for (int j(hed[i]);j;j=e[j].nxt){
int v(e[j].v);
if (v==i || v==S_1 || v==T_1) continue;
if (vis[v]) vis[v]=false;
}
}
vis[S_1]=vis[T_1]=1;
//Spfa
memset (dis,inf,sizeof dis);
int h(0),t(0);
que[++h]=T_1;
dis[T_1]=0;
inss[T_1]=true;
while (t<h){
int x(que[++t]);inss[x]=false;
for (int i(hed[x]);i;i=e[i].nxt){
int v(e[i].v);
if (!vis[v]) continue;
if (dis[v] > dis[x] + 1 ) dis[v]=dis[x]+1;
else continue;
if (!inss[v]) inss[v]=true,que[++h]=v;
}
}
if (dis[S_1]==inf) puts("-1");
else printf("%d\n",dis[S_1]);
return 0;
}