图论——单源最短路的综合应用

[CQOI2005] 新年好

重庆城里有 nnn 个车站,mmm 条双向公路连接其中的某些车站。每两个车站最多用一条公路连接,从任何一个车站出发都可以经过一条或者多条公路到达其他车站,但不同的路径需要花费的时间可能不同。在一条路径上花费的时间等于路径上所有公路需要的时间之和。

佳佳的家在车站 111,他有五个亲戚,分别住在车站 a,b,c,d,ea,b,c,d,ea,b,c,d,e。过年了,他需要从自己的家出发,拜访每个亲戚(顺序任意),给他们送去节日的祝福。怎样走,才需要最少的时间?

输入格式

第一行:n,mn,mn,m,分别为车站数目和公路的数目。

第二行:a,b,c,d,ea,b,c,d,ea,b,c,d,e,分别为五个亲戚所在车站编号。

以下 mmm 行,每行三个整数 x,y,tx,y,tx,y,t,为公路连接的两个车站编号和时间。

输出格式

仅一行,包含一个整数 TTT,为最少的总时间。保证 T≤109T\le 10^9T109

样例输入 #1

6 6
2 3 4 5 6
1 2 8
2 3 3
3 4 4
4 5 5
5 6 2
1 6 7

样例输出 #1

21

对于 40%40\%40% 的数据,有 1≤n≤5001≤n≤5001n5001≤m≤20001≤m≤20001m2000

对于 100%100\%100% 的数据,有 1≤n≤500001≤n≤500001n500001≤m≤1000001≤m≤1000001m1000001≤a,b,c,d,e≤n1\le a,b,c,d,e≤n1a,b,c,d,en1≤x,y≤n1≤x,y≤n1x,yn1≤t≤100001≤t≤100001t10000
本题要求的不是单源点最短路,而是从起点开始,走过a,b,c,d,ea,b,c,d,ea,b,c,d,e五个点的最短距离。

考虑枚举遍历从1开始走遍a,b,c,d,ea,b,c,d,ea,b,c,d,e点的顺序,方案数为5!5!5!,每一个方案都要走过五条路径,例如方案1−b−a−e−d−c1-b-a-e-d-c1baedc要走过路径(1,b),(b,a),(a,e),(e,d),(d,c)(1,b),(b,a),(a,e),(e,d),(d,c)(1,b),(b,a),(a,e),(e,d),(d,c)。考虑对于每一个方案,都做六遍dijkstra,每次求出来从1,a,b,c,d,e1,a,b,c,d,e1,a,b,c,d,e中一个点到其他点的最短距离,对于该方案所求的结果就是5个点对之间最短路径的和,这样时间复杂度就是O(6!mlogm)O(6!mlogm)O(6!mlogm)。考虑先求出从这六个点出发到其他点的最短路径,在枚举所有方案,这样就起到了一个预处理的左右,时间复杂度为O(6mlogm+5!)O(6mlogm+5!)O(6mlogm+5!)

#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
typedef pair<int,int> PII;
const int N = 50010, M = 1e5 * 2 + 10;
int dist[10][N];
bool st[N];
int h[N], e[M], ne[M], w[M];
int tot;
int source[10];
int n, m;
void add(int a, int b, int c)
{
   
   
    e[tot] = b, ne[tot] = h[a], w[tot] = c, h[a] = tot ++ ;
}
void dijkstra(int start, int dist[])
{
   
   
    memset(dist, 0x3f, N * 4);
    memset(st, 0, sizeof st);
    dist[start] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> heap;
    heap.push({
   
   dist[start], start});
    while (heap.size())
    {
   
   
        auto t = heap.top();
        heap.pop();
        int ver = t.second, distance = t.first;
        if (st[ver]) continue;
        st[ver] = 1;
        for (int i = h[ver]; ~i; i = ne[i])
        {
   
   
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
   
   
                dist[j] = dist[ver] + w[i];
                heap.push({
   
   dist[j], j});
            }
        }
    }
    return ;
}
int dfs(int u, int last, int val)
{
   
   
    if (u == 6) return val;
    int res = 0x3f3f3f3f;
    for (int i = 2; i <= 6
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值