题意:找出一条近最短路,这条近最短路不包含所有最短路的边
先找出所有最短路经过的点。再找最短路,要求使用的边不是最短路上的边(边的两点都是最短路经过的点,而且边长等于两点间的距离,则说明是最短路上的边)。
两次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;
}