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; }
没有人不辛苦,只有人不喊疼