You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

AcWing 1127 香甜的黄油

一、题目描述

农夫John发现了做出全威斯康辛州最甜的黄油的方法:

把糖放在一片牧场上,他知道 N 只奶牛会过来舔它,这样就能做出能卖好价钱的超甜黄油。

当然,他将付出额外的费用在奶牛上。

农夫John很狡猾,就像以前的巴甫洛夫,他知道他可以训练这些奶牛,让它们在听到铃声时去一个特定的牧场。

他打算将糖放在那里然后下午发出铃声,以至他可以在晚上挤奶。

农夫John知道每只奶牛都在各自喜欢的牧场(一个牧场不一定只有一头牛)。

给出各头牛在的牧场和牧场间的路线,找出使 所有牛到达的路程和最短的牧场(他将把糖放在那)。

数据保证至少存在一个牧场和所有牛所在的牧场连通。

输入格式

第一行: 三个数:奶牛数 N,牧场数 P,牧场间道路数 C

第二行到第 N+1 行: 1N 头奶牛所在的牧场号。

N+2 行到第 N+C+1 行:每行有三个数:相连的牧场A、B,两牧场间距 D,当然,连接是双向的。

输出格式 共一行,输出奶牛必须行走的最小的距离和。

二、算法分析

枚举所有点作为特定牧场,求特定牧场到所有点的最短距离

点的个数n= 800,边的个数m=1500

堆优化版dijkstra 复杂度是O(n\times m \times log_2n) = n \times m \times log_2n \approx 800 \times 1500 \times 10 = 1.210^7

三、Dijkstra

#include <bits/stdc++.h>

using namespace std;
typedef pair<int, int> PII;
const int N = 810;  // 牧场数 上限800
const int M = 3000; // 牧场间道路数 上限1450无向图开双倍
const int INF = 0x3f3f3f3f;
// 邻接表
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

int n, p, m; // 三个数:奶牛数 ,牧场数 ,牧场间道路数
int id[N];   // 每只奶牛在哪个牧场
int dis[N];  // 记录起点到任意点的最短路径
bool st[N];  // 标识每个牧场是否入过队列

int dijkstra(int S) {
    memset(st, 0, sizeof st);
    memset(dis, 0x3f, sizeof dis);
    dis[S] = 0;
    priority_queue<PII, vector<PII>, greater<PII>> q;
    q.push({0, S});

    while (q.size()) {
        PII t = q.top();
        q.pop();

        int u = t.second;
        if (st[u]) continue;
        st[u] = true;

        for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (dis[v] > dis[u] + w[i]) {
                dis[v] = dis[u] + w[i];
                q.push({dis[v], v});
            }
        }
    }
    int res = 0;
    for (int i = 1; i <= n; i++) {     // 遍历每只奶牛
        int j = id[i];                 // j号牧场
        if (dis[j] == INF) return INF; // 如果j号牧场失联了则无法获得结果
        res += dis[j];                 // 累加一个最小距离
    }
    return res; // 整体的最小距离
}
int main() {
    memset(h, -1, sizeof h);
    cin >> n >> p >> m;                        // 奶牛数,牧场数,牧场间道路数
    for (int i = 1; i <= n; i++) cin >> id[i]; // 1 到 N 头奶牛所在的牧场号

    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }
    int ans = INF;

    // 枚举每个牧场为出发点,计算它的最短距离和 中的最小值
    for (int i = 1; i <= p; i++) ans = min(ans, dijkstra(i));

    printf("%d\n", ans);
    return 0;
}