[CF1433G] Reducing Delivery Cost - 最短路,思維
阿新 • • 發佈:2020-10-22
Description
給定一張圖 \((n \le 1000, m \le 1000)\),圖上有 \(k\) 對點 \((a_i,b_i)\) 表示有一個運輸專案從 \(a_i\) 運輸到 \(b_i\)。現在你可以選擇一條邊將它的權值變為零,要求最小化所有運輸專案的最短距離的和。
Solution
考慮將每條邊 \(e(u,v)\) 的權值變為 \(0\) 對結果的影響,對於運輸計劃 \((a,b)\),其若不經過 \((u,v)\) 則為其原答案,要麼經過 \((u,v)\) 則答案為 \(\min(d_{a,u}+d_{v,b}, d_{a,v}+d_{u,b})\),二者取最小值即可。
於是我們只需要預處理出所有點對之間的最短路,然後模擬上述過程即可。求所有點對最短路的過程可以用 Dijkstra 做到 \(O(nm \log n)\)
#include <bits/stdc++.h> using namespace std; const int N = 1005; #define reset(x) memset(x,0,sizeof x) #define reset3f(x) memset(x,0x3f,sizeof x) namespace sp { vector<pair<int,int> > g[N]; int n,v0=1,d[N],v[N]; void make(int t1,int t2,int t3) { g[t1].push_back(make_pair(t2,t3)); } void reset_graph() { for(int i=0;i<=n;i++) g[i].clear(); } void solve() { priority_queue<pair<int,int> > qu; reset3f(d);reset(v); d[v0]=0; qu.push(make_pair(0,v0)); while(qu.size()) { int p=qu.top().second,r=qu.top().first; qu.pop(); if(r+d[p]) continue; for(int i=0;i<g[p].size();i++) { int q=g[p][i].first,w=g[p][i].second; if(d[q]>d[p]+w) { d[q]=d[p]+w; qu.push(make_pair(-d[q],q)); } } } } } struct edge {int u,v,w;} ed[N]; int n,m,k,t1,t2,t3,a[N],b[N],d[N][N]; void readdata() { cin>>n>>m>>k; for(int i=1;i<=m;i++) { cin>>t1>>t2>>t3; sp::make(t1,t2,t3); sp::make(t2,t1,t3); ed[i]={t1,t2,t3}; } for(int i=1;i<=k;i++) { cin>>a[i]>>b[i]; } } void presolve() { for(int i=1;i<=n;i++) { sp::v0=i; sp::solve(); for(int j=1;j<=n;j++) d[i][j]=sp::d[j]; } } void solve() { int ans=1e18; for(int i=1;i<=m;i++) { int u=ed[i].u,v=ed[i].v,w=ed[i].w; int tans=0; for(int j=1;j<=k;j++) { tans+=min(d[a[j]][b[j]],min(d[a[j]][u]+d[v][b[j]], d[a[j]][v]+d[u][b[j]])); } ans=min(ans,tans); } cout<<ans<<endl; } signed main() { readdata(); presolve(); solve(); return 0; }