题目描述
“题目名称只是吸引你来做题的啦,其实和题目没什么卵关系:o( ̄▽ ̄)o” —— 历史——殿堂
wpy移情别恋啦,他不喜欢spfa了,现在他喜欢使用dij,但是他又发现了一个新的问题,dij无法跑有负权边的图,于是wpy找到了她的男朋友也就是你来帮忙,为了你晚上的幸福生活,你必须在1秒内帮她解决这个问题,然后蹿到床上。。。balabala(捂脸)。。。。(/ω\)
简单来说,有一张n个点,m条边的有向图,请你给每条边确定一个新的边权(不同边之间可以不同),保证对于任意u,v,在新图上的u到v的最短路上的点和原图上最短路上的点相同且顺序不变。
新的边权要求非负。
输入描述:
第一行两个整数n,m,表示有n个点,m条边。
接下来m行,每行三个数,u,v,w,表示有一条从u到v。
输出描述:
输出m行,每行三个整数u,v,w表示有从u到v的边边权改完后是为w。
ps:按输入顺序输出。
题解
根据spfa的放缩原理 我们可以得知
一定是大于等于0的。
我们假设在新图上从u到v的路径权值为
假设在原图里u->v的最短路径为u->x1->x2->x3->v
那原图的最短路也就是
在我们更改了边权的新图中的最短路为:
也就是:
是一个定值,故我们更改权值之后最短路的节点顺序仍然不变。
所以我们只要把现在的边权规定为即可
代码
/*
* Coder: niiii
* Language: cpp
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+100;
const int mod=1e9+7;
struct node{
int now,to,net,w;
}s[N];
int head[N],dis[N],in[N];
int tot=0;
void add(int u,int v,int w){
s[++tot]={u,v,head[u],w};
head[u]=tot;
}
void spfa(){
queue<int> Q;
in[0]=1;
dis[0]=0;
Q.push(0);
while(!Q.empty()){
int now=Q.front();
Q.pop();
in[now]=0;
for(int i=head[now];~i;i=s[i].net){
int to=s[i].to;
if(dis[to]>dis[now]+s[i].w){
dis[to]=dis[now]+s[i].w;
if(!in[to]){
Q.push(to);
in[to]=1;
}
}
}
}
}
int main(){
ios::sync_with_stdio(false);
int n,m;
memset(dis,0x3f,sizeof(dis));
memset(head,-1,sizeof(head));
cin>>n>>m;
for(int i=1;i<=m;++i){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
for(int i=1;i<=n;++i){
add(0,i,0);
}
spfa();
for(int i=1;i<=m;++i){
cout<<s[i].now<<" "<<s[i].to<<" "<<dis[s[i].now]-dis[s[i].to]+s[i].w<<endl;
}
}
/*
(u,x1)+(x1,x2)+(x2,x3)+(x2,t)
*/
京公网安备 11010502036488号