题意:找出一条近最短路,这条近最短路不包含所有最短路的边
先找出所有最短路经过的点。再找最短路,要求使用的边不是最短路上的边(边的两点都是最短路经过的点,而且边长等于两点间的距离,则说明是最短路上的边)。
两次spfa分别找到起点和终点的最短距离,当每一个点的两个最短距离加起来刚好是起点到终点的距离时,说明该点在最短路上。
做这道题比较顺利,直接贴代码
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> using namespace std; const int N = 509; const int M = 10009; const int INF = 0x3f3f3f3f; int n,m,st,en; struct LL{ int to,nex,dis; } L[M],RL[M]; int F[N],cnt,RF[N],Rcnt; int dis[N],redis[N]; bool visit[N]; void make_mindis() { memset(visit,false,sizeof(visit)); queue<int> que; while(!que.empty()) que.pop(); memset(dis,INF,sizeof(dis)); que.push(st); visit[st] = true; dis[st] = 0; while(!que.empty()) { int e=que.front(); que.pop(); // cout<<e<<endl; visit[e] = false; for(int i=F[e];i;i=L[i].nex) { int to = L[i].to; //cout<<to<<"kk"<<endl; if(dis[to]>dis[e]+L[i].dis) { dis[to]=dis[e]+L[i].dis; if(!visit[to]) { visit[to] = true; que.push(to); } } } } } void make_minredis() { memset(visit,false,sizeof(visit)); queue<int> que; while(!que.empty()) que.pop(); memset(redis,INF,sizeof(redis)); que.push(en); visit[en] = true; redis[en] = 0; while(!que.empty()) { int e=que.front(); que.pop(); visit[e] = false; for(int i=RF[e];i;i=RL[i].nex) { int to = RL[i].to; if(redis[to]>redis[e]+RL[i].dis) { redis[to]=redis[e]+RL[i].dis; if(!visit[to]) { visit[to] = true; que.push(to); } } } } } void add(int f,int t,int dis) { L[cnt].dis = dis; L[cnt].nex = F[f]; L[cnt].to = t; F[f] = cnt; cnt++; } void Radd(int f,int t,int dis) { RL[Rcnt].dis = dis; RL[Rcnt].nex = RF[f]; RL[Rcnt].to = t; RF[f] = Rcnt; Rcnt++; } void init() { int f,t,dis; cnt = 1;Rcnt = 1; memset(F,0,sizeof(F)); memset(RF,0,sizeof(RF)); for(int i=0;i<m;i++) { scanf("%d%d%d",&f,&t,&dis); add(f,t,dis); Radd(t,f,dis); } } bool minpoint[N]; struct nod{ int to,dis; bool operator<(const nod t) const { return dis>t.dis; } }; int ansdis[N]; void solve() { make_mindis(); if(dis[en] == INF) { printf("-1\n"); return ; } make_minredis(); int D = dis[en]; for(int i=0;i<n;i++) if(dis[i]+redis[i]==D) minpoint[i] = true; else minpoint[i] =false; // for(int i=0;i<n;i++) if(minpoint[i]) cout<<i<<" ";cout<<endl; priority_queue<nod> que; while(!que.empty()) que.pop(); memset(visit,false,sizeof(visit)); memset(ansdis,INF,sizeof(ansdis)); nod e,t; e.to = st,e.dis =0; ansdis[e.to] = 0; que.push(e); while(!que.empty()) { e = que.top(); que.pop(); if(visit[e.to]) continue; visit[e.to] = true; for(int i=F[e.to];i;i=L[i].nex) { int to = L[i].to; if(visit[to]) continue; if(ansdis[to]>ansdis[e.to]+L[i].dis) { if(minpoint[e.to]&&minpoint[to]&&L[i].dis==abs(dis[e.to]-dis[to])) continue; ansdis[to] = ansdis[e.to]+L[i].dis; t.dis = ansdis[to]; t.to = to; que.push(t); } } } if(ansdis[en]==INF) { printf("-1\n"); return ; } else { printf("%d\n",ansdis[en]); } } int main() { freopen("in.txt","r",stdin); while(~scanf("%d%d",&n,&m)&&(n+m)) { scanf("%d%d",&st,&en); init(); solve(); } return 0; }