题解: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; }//~*完结撒花*~
本文作者:红枫初十
本文链接:https://www.cnblogs.com/Red-maple/p/18710311
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现