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;
}
posted @ 2020-10-23 21:16  EchoZQN  阅读(180)  评论(0编辑  收藏  举报