题解:SP3405 SAMER08A - Almost Shortest Path
由于洛谷 RemoteJudge 的一些问题,导致我在洛谷上没有 AC 记录,但在 SPOJ 上已 AC。link
题意
让你在一个有向图中,求出一条与所有最短路无重边的最短路长度,即将原图中所有最短路经过的边删掉,在新图中求最短路长度,若没有这条边(即删边后无法到达终点),就输出
注意
-
体面翻译中的
1\le M\le N-1 是假的,看样例都看的出来。原题面中给的是1\le M \le 10^4 ; -
这题有多组数据,由
N,M 来判断,若输入的N,M 的值都为0 ,你就该结束程序了。
思路
基本上题意看懂了,这一题就非常简单了。
跑两遍最短路(我写的 dijkstra)。
第一遍将所有最短路都求出来,在松弛的时候记录转移路径:
- 若更新值与原来值相等,就记录这一转移路径;
- 若更新值小于原来值,就覆盖掉已记录的转移路径,记录这一条,并将值压入队列;
- 若更新值大于原来值,什么都不用干。
然后从终点往回,沿着记录的转移路径边搜索,边标记边(即把这个边删除),边界为搜到起点。
第二遍就比较简单,从起点开始,只要要经过一条已标记的边时,就跳过不处理,约等于删边。由于我写的是 dijkstra,所以找到的第一条到达终点的路径就是最短路,直接输出返回即可,若到队列为空依然没找到,那就输出
时间复杂度
代码
//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;
}//~*完结撒花*~