题解:SP3405 SAMER08A - Almost Shortest Path

· · 题解

由于洛谷 RemoteJudge 的一些问题,导致我在洛谷上没有 AC 记录,但在 SPOJ 上已 AC。link

题意

让你在一个有向图中,求出一条与所有最短路无重边的最短路长度,即将原图中所有最短路经过的边删掉,在新图中求最短路长度,若没有这条边(即删边后无法到达终点),就输出 -1

注意

思路

基本上题意看懂了,这一题就非常简单了。

跑两遍最短路(我写的 dijkstra)。

第一遍将所有最短路都求出来,在松弛的时候记录转移路径:

然后从终点往回,沿着记录的转移路径边搜索,边标记边(即把这个边删除),边界为搜到起点。

第二遍就比较简单,从起点开始,只要要经过一条已标记的边时,就跳过不处理,约等于删边。由于我写的是 dijkstra,所以找到的第一条到达终点的路径就是最短路,直接输出返回即可,若到队列为空依然没找到,那就输出 -1

时间复杂度 O(n \log n)

代码

//by _maple_leaf_ uid:964876
const int N=1145,M=11451;
int n,m,s,t;
struct node{
    int u,v,w,n;
}e[M];
int head[N],cnt;
void add(int u,int v,int w){
    e[++cnt]={u,v,w,head[u]};
    head[u]=cnt;
}
bool vis[M];
int dis[N];
vector<int>la[N];
priority_queue<pii,vector<pii>,greater<pii> >q;
void dij1(){
    memset(dis,0x3f,sizeof dis);
    dis[s]=0;
    q.push({0,s});
    int temp=-1;
    while(!q.empty()){
        int nw=q.top().second;
        q.pop();
        if(nw==t){
            if(temp==-1||dis[nw]<=temp){
                temp=dis[nw];
            }else return ;//优化
            continue;
        }
        for(int i=head[nw];i;i=e[i].n){
            int to=e[i].v,d=e[i].w;
            if(dis[nw]+d<dis[to]){//小于
                dis[to]=dis[nw]+d;
                la[to].clear();//覆盖
                la[to].push_back(i);//记录
                q.push({dis[nw]+d,to});
            }else if(dis[nw]+d==dis[to])la[to].push_back(i);//等于
        }
    }
}
void dfs(int nw){
    if(nw==s)return;//边界
    for(auto i:la[nw]){
        vis[i]=1;
        dfs(e[i].u);//u是这条边的起点,往回找
    }la[nw].clear();
}
void dij2(){
    while(!q.empty())q.pop();
    memset(dis,0x3f,sizeof dis);
    dis[s]=0;
    q.push({0,s});
    while(!q.empty()){
        int nw=q.top().second;
        q.pop();
        if(nw==t){
            write(dis[nw],1);//直接输出
            return ;//返回即可
        }
        for(int i=head[nw];i;i=e[i].n){
            if(vis[i])continue;
            int to=e[i].v,d=e[i].w;
            if(dis[to]>dis[nw]+d){
                dis[to]=dis[nw]+d;
                q.push({dis[to],to});
            }
        }
    }puts("-1");//无解
}
signed main(){
    while(1){
        n=read(),m=read();
        if(!n&&!m)return 0;
        cnt=0;
        memset(head,0,sizeof head);
        memset(vis,0,sizeof vis);
        s=read(),t=read();
        for(int i=1;i<=m;i++){
            int u=read(),v=read(),w=read();
            add(u,v,w);
        }
        dij1();
        dfs(t);
        dij2();
    }
    return 0;
}//~*完结撒花*~