1. 程式人生 > 實用技巧 >G. Reducing Delivery Cost 思維+最短路

G. Reducing Delivery Cost 思維+最短路

G. Reducing Delivery Cost 思維+最短路

題目大意:

n個點,m條邊,q條路經,每條路徑有一個起點一個終點,你最多可以選擇刪掉一條邊,問刪完之後q條路經距離的最小值之和,距離表示起點到終點的最短距離。

題解:

先預處理任意兩個點之間的最短距離,列舉這m條邊,查刪掉之後的距離,求最小值。

注意:如果一條邊刪去,那麼最短距離的更新有兩種可能

  • 刪掉前後都不是最短距離的一部分,最短距離不變
  • 刪掉之後成為了最短距離的一部分,那麼就是原來的點到兩端的距離+0

最後的複雜度就是 \(O(n*m+m*k*logn)\)

這個題目主要要明白,一條邊變成0之後,應該如何更新這個最短路。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1010;
typedef long long ll;
int head[maxn],flag[maxn<<1],to[maxn<<1],nxt[maxn<<1],cnt,cost[maxn],w[maxn<<1];
void add(int u,int v,int i,int c){
	++cnt,to[cnt] = v,flag[cnt] = i,nxt[cnt] = head[u],w[cnt] = c,head[u] = cnt;
	++cnt,to[cnt] = u,flag[cnt] = i,nxt[cnt] = head[v],w[cnt] = c,head[v] = cnt;
}
struct node{
	int u,d;
	node(int u=0,int d=0):u(u),d(d){}
	bool operator<(const node&a)const{
		return a.d<d;
	}
};
int vis[maxn],d[maxn][maxn],n,m,k,num[maxn];
priority_queue<node>que;
void dij(int s){
	int pos = s;
	while(!que.empty()) que.pop();
	for(int i=1;i<=n;i++) d[pos][i] = inf,vis[i] = false;
	que.push(node(s,0));
	d[pos][s] = 0;
	while(!que.empty()){
		node x = que.top();que.pop();
		int u = x.u;
		if(vis[u]) continue;
		vis[u] = true;
		for(int i=head[u];i;i=nxt[i]){
			int v = to[i];
			if(d[pos][v]>d[pos][u]+w[i]){
				d[pos][v] = d[pos][u] + w[i];
				que.push(node(v,d[pos][v]));
			}
		}
	}
}
int gx[maxn],gy[maxn],ux[maxn],uy[maxn],uw[maxn];
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,i,w);
		cost[i] = w,ux[i] = u,uy[i] = v,uw[i]  =w;
	}
	for(int i=1;i<=k;i++){
		scanf("%d%d",&gx[i],&gy[i]);
		dij(gx[i]),dij(gy[i]);
	}
	ll ans = inf64;
	for(int i=1;i<=m;i++){
		ll sum = 0;
		int x = ux[i],y = uy[i],w = uw[i];
		for(int j=1;j<=k;j++){
			int u = gx[j],v = gy[j];
			sum += min(min(d[u][x]+d[v][y],d[u][y]+d[v][x]),d[u][v]);
		}
		ans = min(ans,sum);
	}
	printf("%lld\n", ans);
	return 0;
}