旅行 题解

题目链接

题意简述

给定一张有向图,求从点 \(A\) 走到点 \(B\) 的一条路径,这条路径满足:

  1. 经过的边的权值总和是 \(P\) 的倍数。
  2. 在满足条件 \(1\) 的情况下,经过的边的权值总和最小。

题目分析

本题可以使用分层图最短路来解决。

仿照动态规划的思想,定义 \(f_{x,y}\) 表示从节点 \(A\) 到达节点 \(x\),经过的边的权值总和 \(\bmod P\) 的值为 \(y\) 时,经过的边的权值总和最小是多少。

然后进行一遍 Dijkstra 算法,设当前考虑的节点为 \(a\),当前经过的边的权值总和 \(\bmod P\) 的值为 \(b\),扫描到一条通向点 \(c\),权值为 \(d\) 的边,在满足“当前位于点 \(c\),经过的边的权值总和 \(\bmod P\) 的值为 \((b+d) \bmod P\)”这个状态没有被访问过的前提下,如果满足 \(f_{c,(b+d) \bmod P} > f_{a,b}+d\),则使用 \(f_{a,b}+d\) 更新 \(f_{c,(b+d) \bmod P}\)

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){register int t1=0,t2=0;register char x=getchar();while(x<'0' ||x>'9'){if(x=='-') t2|=1;x=getchar();}while(x>='0' && x<='9'){t1=(t1<<1)+(t1<<3)+(x^48),x=getchar();}return t2?-t1:t1;}
inline void write(int x){register int sta[35],top=0;if(x<0) putchar('-'),x=-x;do{sta[top++]=x%10,x/=10;}while(x);while(top) putchar(sta[--top]+48);}
int n,m,p,s,t,f[50005][55],pre_now[50005][55],pre_use[50005][55];
bool vis[50005][55];
struct edge{
	int to,l;
};
vector<edge> v[50005];
struct node{
	int now,sum,use;
};
priority_queue<node> q;
bool operator <(const node &a,const node &b){
	return a.sum>b.sum;
}
vector<int> ans;
void get(int x,int y){//通过保存的路径信息得到具体地路径 
	if(!x) return;
	ans.push_back(x);
	get(pre_now[x][y],pre_use[x][y]);
}
signed main(){
	n=read();
	m=read();
	p=read();
	s=read();
	t=read();
	for(int i=1;i<=m;i++){
		int t1=read(),t2=read(),t3=read();
		v[t1].push_back({t2,t3});
	}
	memset(f,0x3f,sizeof(f));
	f[s][0]=0;
	q.push({s,0,0});
	while(!q.empty()){
		node temp=q.top();
		q.pop();
		if(vis[temp.now][temp.use]) continue;
		vis[temp.now][temp.use]=1;
		for(int i=0;i<v[temp.now].size();i++){
			int t1=v[temp.now][i].to,t2=v[temp.now][i].l;
			if(!vis[t1][(temp.use+t2)%p] && f[t1][(temp.use+t2)%p]>f[temp.now][temp.use]+t2){
				f[t1][(temp.use+t2)%p]=f[temp.now][temp.use]+t2;
				pre_now[t1][(temp.use+t2)%p]=temp.now;//保存路径信息 
				pre_use[t1][(temp.use+t2)%p]=temp.use;//同上 
				q.push({t1,f[t1][(temp.use+t2)%p],(temp.use+t2)%p});
			}
		}
	}
	if(f[t][0]==4557430888798830399) puts("jjc fails in travelling");//考虑无法完成的情况
	else{
		write(f[t][0]);
		putchar('\n');
		get(t,0);
		for(int i=ans.size()-1;i>0;i--){
			write(ans[i]);
			putchar('-');
			putchar('>');
		}
		write(ans[0]);
	}
	return 0;
}
posted @ 2024-05-15 15:50  ZnHF  阅读(8)  评论(1编辑  收藏  举报