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
", ans);
return 0;
}