题解: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 中国大陆许可协议进行许可。

posted @   红枫初十  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起