1. 程式人生 > 實用技巧 >題解 CF1433G 【Reducing Delivery Cost】

題解 CF1433G 【Reducing Delivery Cost】

題目連結

Solution CF1433G Reducing Delivery Cost

題目大意:給定一張 \(n\) 個點 \(m\) 條邊的帶權無向圖,記 \(d(u,v)\)\(u\)\(v\) 的最短路,給定 \(k\) 個點對 \((a_i,b_i)\)。你可以使任意一條邊的邊權變為 \(0\),求\(\sum_{i=1}^kd(a_i,b_i)\) 的最小值

最短路


分析:

我們先預處理出原圖兩兩之間的最短路

將任意一邊的權值置為 \(0\) 之後,最短路徑可以分為兩類:經過 \(0\) 邊的,和不經過 \(0\) 邊的

不經過的 \(0\) 邊的我們已經預處理出來了

假設 \(0\)

邊為 \((a,b)\),我們要求的是 \(d(u,v)\),那麼\(d(u,v)=d(u,a)+ d(b,v)\)

由於是無向圖,要考慮 \((a,b)\)\((b,a)\) 兩種情況,然後依次列舉每條邊求解即可

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <queue>
#include <utility>
using namespace std;
const int maxn = 1024;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
struct edge{
	int u,v,d;
	bool operator == (const edge &rhs)const{
		if((u == rhs.u) && (v == rhs.v))return true;
		if((v == rhs.u) && (u == rhs.v))return true;
		return false;
	}
};
vector<edge> G[maxn],edges;
vector<pair<int,int>> vec;
inline void addedge(int u,int v,int d){
	G[u].push_back(edge{u,v,d});G[v].push_back(edge{v,u,d});
	if(u > v)swap(u,v);
	edges.push_back(edge{u,v,d});
}
int dis[maxn][maxn],vis[maxn];
struct node{
	int u,h;
	inline bool operator < (const node &rhs)const{
		return h > rhs.h;
	}
};
inline void dijkstra(int s){
	memset(dis[s],0x3f,sizeof(dis[s]));
	memset(vis,0,sizeof(vis));
	priority_queue<node> q;
	dis[s][s] = 0;
	q.push(node{s,0});
	while(!q.empty()){
		int u = q.top().u;q.pop();
		if(vis[u])continue;
		vis[u] = 1;
		for(auto e : G[u]){
			if(dis[s][u] + e.d < dis[s][e.v]){
				dis[s][e.v] = dis[s][u] + e.d;
				q.push(node{e.v,dis[s][e.v]});
			}
		}
	}
}
int n,m,k,ans = 0x7fffffff;
int main(){
	n = read(),m = read(),k = read();
	for(int u,v,d,i = 1;i <= m;i++)
		u = read(),v = read(),d = read(),addedge(u,v,d);
	for(int u,v,i = 1;i <= k;i++){
		u = read(),v = read();
		vec.push_back(make_pair(u,v));
	}
	for(int i = 1;i <= n;i++)dijkstra(i);
	for(auto e : edges){
		int tmp = 0;
		for(auto p : vec){
			int u = p.first,v = p.second;
			tmp += min(dis[u][v],min(dis[u][e.u] + dis[v][e.v],dis[u][e.v] + dis[v][e.u]));
		}
		ans = min(ans,tmp);
	}
	printf("%d\n",ans);
	return 0;
}