最短缩减路径

最短缩减路径

给定一张无向图,你可以让任意一条边的权值减半,求起点到终点的最短路径。

点数 \(\le 500\);边数 \(\le 50000\)\(1\le\) 边权 \(\le 500000\),且均为偶数。

本题有两种思路:

  1. 分层图,就只有一条边,只需要分两层,是比较简单的模型应用。
  2. 计算从起点、终点到其他所有点的距离,然后枚举中间的任意一条边(方向不同视作不同的边),计算三部分:起点到边一端、这条边的权值减半、边另一端到终点,由于是无向图,所以从终点到其他所有点的距离等价于从其他所有点到终点的距离,把三部分相加即可。

分层图

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while

const int N=1010,M=6*50010;
int n,m,sta,en,dis[N];
int h[N],e[M],ne[M],idx,w[M];//don't forget memset h!
bool st[N];
struct node{
	int x,dis;
	bool operator<(const node &y)const{
		return dis>y.dis;
	}
};
priority_queue<node>q;
void add(int a,int b,int c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dijkstra(int s){
	memset(dis,0x3f,n*4+4);
	memset(st,0,n+1);
	dis[s]=0;
	q.push({s,0});
	while(!q.empty()){
		auto t=q.top();q.pop();
		int x=t.x,dist=t.dis;
		// printf("x=%d,dis={%d}\n",x,dist);
		if(st[x])continue;
		if(x==en){
			printf("%d",dis[x]);
			return;
		}
		st[x]=1;
		Ed{
			int j=e[i];
			if(dis[j]>dist+w[i]){
				dis[j]=dist+w[i];
				q.push({j,dis[j]});
			}
		}
	}
	// E(i, n)printf("%d ",dis[i]);
	// puts("");
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
	scanf("%d%d",&n,&m);
	memset(h,-1,n*8+4);
	E(i, m){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c),add(b,a,c);
		add(a,b+n,c>>1),add(b,a+n,c>>1);
		add(a+n,b+n,c),add(b+n,a+n,c);
	}
	scanf("%d%d",&sta,&en);
	if(sta==en)return puts("0"),0;
	en+=n;
	n<<=1;
	dijkstra(sta);
	return 0;
}

枚举边

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while

const int N=510,M=2*50010;
int n,m,sta,en,dis[N],dis2[N];
int h[N],e[M],ne[M],idx,w[M];//don't forget memset h!
bool st[N];
struct node{
	int x,dis;
	bool operator<(const node &y)const{
		return dis>y.dis;
	}
};
priority_queue<node>q;
void add(int a,int b,int c){
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dijkstra(int s,int dis[]){
	memset(dis,0x3f,n*4+4);
	memset(st,0,n+1);
	dis[s]=0;
	q.push({s,0});
	while(!q.empty()){
		auto t=q.top();q.pop();
		int x=t.x,dist=t.dis;
		// printf("x=%d,dis={%d}\n",x,dist);
		if(st[x])continue;
		st[x]=1;
		Ed{
			int j=e[i];
			if(dis[j]>dist+w[i]){
				dis[j]=dist+w[i];
				q.push({j,dis[j]});
			}
		}
	}
	// E(i, n)printf("%d ",dis[i]);
	// puts("");
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
	scanf("%d%d",&n,&m);
	memset(h,-1,n*4+4);
	E(i, m){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c),add(b,a,c);
	}
	scanf("%d%d",&sta,&en);
	if(sta==en)return puts("0"),0;
	dijkstra(sta,dis);
	dijkstra(en,dis2);
	int ans=1e9;
	L(i, idx){
		ans=min(ans,dis[e[i^1]]+(w[i]>>1)+dis2[e[i]]);
	}
	printf("%d",ans);
	return 0;
}
posted @ 2023-08-29 08:02  wscqwq  阅读(13)  评论(0编辑  收藏  举报