题解:SP3405 SAMER08A - Almost Shortest Path

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

题意

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

注意

  • 体面翻译中的 \(1\le M\le N-1\) 是假的,看样例都看的出来。原题面中给的是 \(1\le M \le 10^4\)

  • 这题有多组数据,由 \(N,M\) 来判断,若输入的 \(N,M\) 的值都为 \(0\),你就该结束程序了。

思路

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

跑两遍最短路(我写的 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;
}//~*完结撒花*~
posted @ 2025-02-11 18:46  BriskCube  阅读(38)  评论(0)    收藏  举报