Gym - 101630J Journey from Petersburg to Mosc (最短路徑) (2017–2018, NEERC – Northern Eurasia Finals)
阿新 • • 發佈:2018-11-17
題意:求最短路徑,其中最短路徑只算前K大的邊。
解題思路:列舉所有邊權,然後對原圖重新建圖,如果邊權小於當前列舉值,那麼把他權值置為0,大於的話,讓他減去當前列舉的大小。然後跑最短路即可。最後用d[N]+K*c[i]更新答案即可。
以下是簡單的證明:
首先只算前k大的邊的最短路肯定比真正的最短路要小。
假設第K+1大的邊為X,那麼在最短路中,小於等於X的邊的權值可以視為0.
所以我們只需要列舉第K+1大的邊的權值即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAXN=3005; struct edge{ int u,v,next; ll w; }ye[MAXN*2],e[MAXN*2]; int head[MAXN],edge_num; void insert_edge(int u,int v,ll w){ ye[edge_num].u=u; ye[edge_num].v=v; ye[edge_num].w=w; ye[edge_num].next=head[u]; head[u]=edge_num++; } int N,M,K; ll c[MAXN*2]; void rebuild(ll x){ for(int i=0;i<edge_num;i++){ e[i]=ye[i]; if(ye[i].w<x){ e[i].w=0; } else e[i].w-=x; } } ll d[MAXN]; bool vis[MAXN]; priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> >> que; ll dij(){ memset(d,0x3f,sizeof(d)); memset(vis,0,sizeof(vis)); que.push({0,1}); d[1]=0; while(!que.empty()){ auto tp=que.top(); que.pop(); int u=tp.second; if(vis[u]) continue; vis[u]=1; for(int i=head[u];~i;i=e[i].next){ int v=e[i].v; if(d[v]>d[u]+e[i].w){ d[v]=d[u]+e[i].w; que.push({d[v],v}); } } } return d[N]; } int main() { memset(head,-1,sizeof(head)); edge_num=0; scanf("%d%d%d",&N,&M,&K); int u,v; ll w; for(int i=0;i<M;i++){ scanf("%d%d%lld",&u,&v,&w); insert_edge(u,v,w); insert_edge(v,u,w); c[i]=w; } rebuild(0); ll ans=dij(); for(int i=0;i<M;i++){ rebuild(c[i]); ll p=dij(); ans=min(ans,p+K*c[i]); } printf("%lld\n",ans); return 0; }