1. 程式人生 > 實用技巧 >Codeforces1433G Reducing Delivery Cost

Codeforces1433G Reducing Delivery Cost

Solution

一開始的想法是把所有最短路在途中標記出來,然後取一個 經過次數\(\times\)邊權 最大的邊邊權置為 \(0\),然後就成為了標準錯解,WA ON TEST 2。這是因為刪之前的最短路徑和刪之後的最短路徑不一定重合,這點從樣例二就可以看出來。

\(\text{dis}(x,y)\) 表示 \(x\)\(y\) 的最短距離,那麼我們要考慮的就是將一條邊 \((u,v)\) 邊權置零後 \(\text{dis}(a_i,b_i)\) 會如何變化。如果想要讓 \(\text{dis}(a_i,b_i)\) 變小,則最短路徑一定會經過 \((u,v)\) 這條邊。顯然,此時 \(\text{dis}(a_i,b_i)=\min\{\text{dis}(a_i,b_i),\text{dis}(a_i,u)+\text{dis}(b_i,v),\text{dis}(a_i,v)+\text{dis}(b_i,u)\}\)

\(\text{dis}\) 可以跑 \(n\) 遍 Dijkstra 預處理,然後列舉哪條邊被刪掉即可。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
inline void read(int &x)
{
	x=0; int f=1;
	char c=getchar();
	while(c<'0' || c>'9')
	{
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0' && c<='9')
	{
		x=(x<<1)+(x<<3)+(c^48);
		c=getchar(); 
	}
	x*=f;
}
const int N=1000,M=2000,INF=0x3f3f3f3f;
int head[N+10],ver[M+10],nxt[M+10],edge[M+10],tot=1;
void add(int x,int y,int z)
{
	ver[++tot]=y;
	edge[tot]=z;
	nxt[tot]=head[x];
	head[x]=tot;
}
int dis[N+10][N+10];
bool vis[N+10];
int n,m,k;
void dij(int S)
{
	for(int i=1;i<=n;i++) dis[S][i]=INF;
	dis[S][S]=0;
	memset(vis,0,sizeof(vis));
	priority_queue<pair<int,int> > que;
	que.push(make_pair(0,S));
	while(!que.empty())
	{
		int x=que.top().second; que.pop();
		if(vis[x]) continue;
		vis[x]=1;
		for(int i=head[x];i;i=nxt[i])
		{
			int y=ver[i],z=edge[i];
			if(dis[S][x]+z<dis[S][y])
			{
				dis[S][y]=dis[S][x]+z;
				que.push(make_pair(-dis[S][y],y));
			}
		}
	}
}
struct node
{
	int a,b;
//	bool operator < (const node &x) const {return a==x.a?b<x.b:a<x.a;}
//	bool operator == (const node &x) const {return a==x.a && b==x.b;}
}s[N+10];
int U[N+10],V[N+10];
int main()
{
	read(n);read(m);read(k);
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		read(u);read(v);read(w);
		U[i]=u;V[i]=v;
		add(u,v,w);
		add(v,u,w);
	}
	for(int i=1;i<=n;i++) dij(i);
	for(int i=1;i<=k;i++) 
	{
		read(s[i].a);
		read(s[i].b);
	}
//	sort(s+1,s+k+1);
//	k=unique(s+1,s+k+1)-s-1;
	int ans=INF;
	for(int i=1;i<=m;i++)
	{
		int sum=0;
		for(int j=1;j<=k;j++)
			sum+=min(dis[s[j].a][s[j].b],min(dis[s[j].a][U[i]]+dis[V[i]][s[j].b],dis[s[j].a][V[i]]+dis[U[i]][s[j].b]));
		ans=min(ans,sum);
	}
	printf("%d",ans);
	return 0;
}