NC20684 wpy的请求(思维)

题目是有向图,并且要求我们最短路上的点和顺序都不能变

看上去无从下手又有迹可循。

我们假设两点之间的最短路是a ,x1,x2,x3,b

那么把他们的权值列出来后发现就是一堆边权。

我们想要的是对于每一条最短路,再修改后他们仍是最短的

这就启发我们,修改后他们之间的这些权值一定是原权值+一个定量。这样对于每条路也还是最小的

又因为每条边都要大于0,可以想到我们在做最短路放缩的时候,用到了dis[b]>=dis[a]+w这个不等式(当然我想不到)

所有做一遍spfa后最后所有点的都是dis[b]<=dis[a]+w,所以dis[a]-dis[b]+w>=0,这个刚好是大于等于0,并且由于在一条路上,他们加减抵消,到最后最短路就是原最短路+一个定值

完美符合题目要求

这题虽然有迹可循,但是我感觉我还是很难想到

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=1e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int st[N];
int dis[N];
struct node{
    int a,b,c;
}s[N];
vector<pll> g[N];
void spfa(int x){
    queue<int> q;
    memset(dis,0x3f,sizeof dis);
    int i;
    dis[x]=0;
    q.push(x);
    st[x]=1;
    while(q.size()){
        int t=q.front();
        q.pop();
        st[t]=0;
        for(i=0;i<g[t].size();i++){
            int j=g[t][i].first;
            if(dis[j]>dis[t]+g[t][i].second){
                dis[j]=dis[t]+g[t][i].second;
                if(!st[j]){
                    q.push(j);
                    st[j]=1;
                }
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    int i;
    for(i=1;i<=m;i++){
        int a,b,c;
        cin>>a>>b>>c;
        g[a].push_back({b,c});
        s[i]={a,b,c};
    }
    for(i=1;i<=n;i++){
        g[0].push_back({i,0});
    }
    spfa(0);
    for(i=1;i<=m;i++){
        int a=s[i].a,b=s[i].b;
        cout<<a<<" "<<b<<" "<<-dis[b]+dis[a]+s[i].c<<endl;
    }
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/14434001.html