T604037 尖峰时刻

方法思路

  1. 图的表示:将城市和道路表示为图,其中每条道路有一个时间依赖的通行时间。

  2. Dijkstra算法:使用Dijkstra算法来寻找最短路径,但需要调整以处理动态变化的边权。

  3. 时间计算:对于每条道路,计算最优的出发时间t,使得总通行时间最小。最优t大约在sqrt(D_i) - 1附近,因为该值最小化函数t + C_i + D_i / (t + 1)。

  4. 优先队列处理:处理每个城市时,探索所有连接的道路,计算可能的到达时间,并在找到更优时间时更新优先队列。

#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;
}

 

posted @ 2025-04-28 18:03  CRt0729  阅读(12)  评论(0)    收藏  举报