4473: 旅游巴士 [CSP-J 2023]

内存限制:1024 MB 时间限制:10.000 S
评测方式:文本比较 命题人:
提交:7 解决:1

题目描述

样例输入 复制

5 5 3
1 2 0
2 5 1
1 3 0
3 4 3
4 5 1

样例输出 复制

6

提示

#include<bits/stdc++.h>
using namespace std;
//解法1:暴力解法,枚举起始时间+BFS求单源最短路-时间复杂度-O(nq)
const int N = 1e4+10;
int n,m,k;
vector<pair<int,int> > g[N]; //邻接表
bool vis[N]; //标记数组
struct point {
	int v,t;
}; 
int ans=0x3f3f3f3f; //记录最早离开时间 

//bfs求单源最短路
void bfs(point s) {
	queue<point> q;
	q.push(s);vis[s.v] = 1;
	while (!q.empty()) {
		point u=q.front();q.pop();
		if (u.v==n && u.t%k==0) {
			ans=min(ans,u.t);
			return ;
		}
		for(int i=0;i<g[u.v].size();i++) {
			int v=g[u.v][i].first,a=g[u.v][i].second;
			if(u.t>=a && !vis[v]) {
				q.push({v,u.t+1});
				if(v!=n) vis[v]=1;
			}
		}
	}
} 
int main(){
    cin>>n>>m>>k;
    int maxa=0,f=1;
    for(int i=1;i<=m;i++) {
    	int u,v,a;cin>>u>>v>>a;
    	g[ u ].push_back({v,a }); //邻接表存图
		maxa=max(maxa,a);
		if(a!=0) f=0; 
    	
	}
	//特判:当k=1并且f=1本题变成单源最短路问题
	if(k==1&&f==1) bfs({1,0});
	else {
		//枚举起点+单源最短路
		for(int t=0;t<=maxa;t+=k) {
			memset(vis,0,sizeof(vis));
			bfs({1,t});
		} 
	}
	cout<<ans<<endl; 
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
//解法2:每个点到达时间按照对k取余进行分类构建k层分层图,使用堆优化dijkstra跑分层图的最短路,时间复杂度-O(nk*log(nk))
const int N = 1e6 + 10;
vector<pair<int, int>> g[N];//邻接表
int min_dis [N];//最短路数组-最短到达时间
int main() {
  int n, m, k;  cin >> n >> m >> k;
  for (int i = 1; i <= m; i++) {
    int u, v, a;  cin >> u >> v >> a;
    for (int j = 0; j < k; j++) {
      //构建k层分层图,每个点到达时间按照对k取余进行分类
      g[j * n + u].push_back({ (j + 1) % k * n + v,a });
    }
  }
  //初始化最短路数组 
  for (int i = 1; i <= n * k; i++) min_dis[i] = 1e9;

  //用堆优化dijkstra跑分层图求最短路
  priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
  min_dis[1] = 0;   pq.push({ 0,1 });

  while (!pq.empty()) {
    int t = pq.top().first, cur = pq.top().second;  pq.pop();
    if (t <= min_dis[cur]) {
      for (auto e : g[cur]) {
        int tmp = min_dis[cur] + 1;
        //如果到达当前节点的时刻小于当前节点的开放时间,则重置使满足条件的最早到达时间
        if (min_dis[cur] < e.second) tmp += ceil((e.second - min_dis[cur]) * 1.0 / k) * k;
        //更新最短路数组
        if (tmp < min_dis[e.first]) {
          min_dis[e.first] = tmp;
          pq.push({ min_dis[e.first],e.first });
        }
      }
    }
  }
  if (min_dis[n] == 1e9) cout << "-1" << endl;
  else cout << min_dis[n] << endl;
  return 0;
}