T604037 尖峰时刻
方法思路
-
图的表示:将城市和道路表示为图,其中每条道路有一个时间依赖的通行时间。
-
Dijkstra算法:使用Dijkstra算法来寻找最短路径,但需要调整以处理动态变化的边权。
-
时间计算:对于每条道路,计算最优的出发时间t,使得总通行时间最小。最优t大约在sqrt(D_i) - 1附近,因为该值最小化函数t + C_i + D_i / (t + 1)。
-
优先队列处理:处理每个城市时,探索所有连接的道路,计算可能的到达时间,并在找到更优时间时更新优先队列。
#include<bits/stdc++.h> #define ll long long #define tiii tuple<ll,ll,ll> // 定义三元组类型,用于存储道路信息(目标城市,基础时间C,动态参数D) #define pii pair<long long int,long long int> // 定义优先队列中使用的pair类型(时间,城市) #define mt make_tuple // 用于创建tuple的快捷宏 using namespace std; const int N = 2e5 + 10; // 定义最大城市数量 const ll inf = 0x3f3f3f3f; // 定义无穷大值,用于初始化距离 vector<tiii> g[N]; // 邻接表,存储图的连接关系 int n,m; // n-城市数量,m-道路数量 ll dis[N],vis[N]; // dis数组存储到达每个城市的最早时间,vis数组标记是否已处理 int f[N]; // 并查集数组,用于检查连通性 // 并查集查找函数 int find(int x) { if(f[x] != x) f[x] = find(f[x]); // 路径压缩 return f[x]; } // 并查集合并函数 void merge(int x,int y) { int fx = find(x),fy = find(y); f[fy] = fx; // 合并两个集合 } // Dijkstra算法实现 void dijkstra(int s) { memset(dis,inf,sizeof(dis)); // 初始化所有城市到达时间为无穷大 dis[s] = 0; // 起始城市到达时间为0 priority_queue<pii,vector<pii>,greater<pii> > q; // 小顶堆,按时间排序 q.push({0,s}); // 初始状态:时间0,城市s while(q.size()) { ll x = q.top().second; q.pop(); // 取出当前最早到达的城市 if(vis[x]) continue; // 如果已处理则跳过 vis[x] = 1; // 标记为已处理 for(int i = 0; i < g[x].size(); i++) // 遍历所有邻接道路 { ll y = get<0>(g[x][i]),c = get<1>(g[x][i]),d = get<2>(g[x][i]); // 获取目标城市、基础时间C和动态参数D ll t; // 计算最优出发时间t if(dis[x] <= round(sqrt(d)) - 1) t = round(sqrt(d)) - 1; // 如果当前时间小于最优时间,取最优时间 else t = dis[x]; // 否则取当前时间 if(dis[y] > t + c + d / (t + 1)){ // 如果找到更早到达时间 dis[y] = t + c + d / (t + 1); // 更新到达时间 q.push({dis[y],y}); // 加入优先队列 } } } } int main() { cin >> n >> m; for(int i = 1; i <=n ; i++) f[i] = i; // 初始化并查集 for(int i = 1; i <= m; i++) { int x,y,c,d; cin >> x >> y >> c >> d; g[x].push_back(mt(y,c,d)); // 添加双向道路 g[y].push_back(mt(x,c,d)); if(find(x) != find(y)) merge(x,y); // 合并连通的城市 } dijkstra(1); // 从城市1开始计算最短时间 if(find(1) != find(n)) cout << -1; // 如果不连通输出-1 else cout << dis[n]; // 否则输出最早到达时间 return 0; }

浙公网安备 33010602011771号