题解 洛谷 Luogu P1828 [USACO3.2] 香甜的黄油 Sweet Butter 最短路 堆优化Dijkstra Floyd C++

题目

传送门

P1828 USACO3.2 香甜的黄油 Sweet Butter - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/problem/P1828

思路

以每头奶牛所在的牧场为起点,求得到全图各个点的最短距离

再枚举全图所有点,计算从所有起点到某点的距离之和,取最小值即可

可以循环依次跑 Dijkstra,也可跑一遍 Floyd

后者更好写,但前者更快,实测前者时间效率约为后者的 6 倍

细节

每个牧场可能有不止一头奶牛,最后结算的距离需要乘上每个牧场的奶牛的头数

代码

堆优化Dijkstra

cpp 复制代码
#include <map>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <iostream>
using namespace std;
typedef pair<int, int> PII;
constexpr int C = 501, N = 801;
vector<PII> to[N];
map<int, int> cow;
int n, m, c, x, dist[C][N], cnt, ans = 1E9; //dist 记录不同起点跑出来的 Dijkstra 的结果
void Dijkstra(int start, int num) //起点,奶牛头数
{
    priority_queue<PII, vector<PII>, greater<PII>> q;
    bool mk[N]{};
    dist[cnt][start] = 0;
    q.emplace(0, start);
    while (q.size()) //真是模模又板板啊
    {
        int x = q.top().second;
        q.pop();
        if (mk[x]) continue;
        mk[x] = true;
        for (auto& z : to[x])
        {
            int X = z.first, w = z.second;
            if (dist[cnt][x] + w < dist[cnt][X])
            {
                dist[cnt][X] = dist[cnt][x] + w;
                q.emplace(dist[cnt][X], X);
            }
        }
    }
    for (int i = 1; i <= n; ++i) dist[cnt][i] *= num; //结果要乘以奶牛头数
    ++cnt; //用 cnt 分配每轮 Dijkstra 用到的 dist 的第一个下标,最后 cnt = cow.size()
}
int main()
{
    ios::sync_with_stdio(false); cin.tie(0);
    memset(dist, 0x3f, sizeof(dist)); //别忘了初始化
    cin >> c >> n >> m;
    while (c--) cin >> x, ++cow[x]; //first 存奶牛所在的牧场,second 存该牧场有多少头奶牛
    while (m--)
    {
        int x, y, w;
        cin >> x >> y >> w;
        to[x].emplace_back(y, w);
        to[y].emplace_back(x, w);
    }
    for (auto& z : cow) Dijkstra(z.first, z.second); //循环跑 Dijkstra
    for (int i = 1; i <= n; ++i)
    {
        int sum = 0;
        for (int j = 0; j < cnt; ++j)
        {
            if (dist[j][i] == dist[0][0]) { sum = 1E9; break; } //可能有无法到达的牧场,遇到直接终止
            sum += dist[j][i];
        }
        ans = min(ans, sum);
    }
    cout << ans;
    return 0;
}

Floyd

cpp 复制代码
#include <cstring>
#include <vector>
#include <algorithm>
#include <map>
#include <iostream>
using namespace std;
constexpr int N = 801;
map<int, int> cow;
int n, m, c, x, dist[N][N], ans = 1E9;
int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    memset(dist, 0x3f, sizeof(dist));
    cin >> c >> n >> m;
    while (c--) cin >> x, ++cow[x]; //first 存奶牛所在的牧场,second 存该牧场有多少头奶牛
    for (int i = 1; i <= n; ++i) dist[i][i] = 0; //自己到自己的距离是 0,别忘了
    while (m--)
    {
        int x, y, w;
        cin >> x >> y >> w;
        dist[x][y] = dist[y][x] = min(dist[x][y], w); //去重边
    }
    for (int k = 1; k <= n; ++k) //真是模模又板板啊
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
    for (int i = 1; i <= n; ++i)
    {
        int sum = 0;
        for (auto& z : cow)
        {
            if (dist[z.first][i] == dist[0][0]) { sum = 1E9; break; } //无法到达的点
            sum += dist[z.first][i] * z.second; //别忘了乘以奶牛头数
        }
        ans = min(ans, sum);
    }
    cout << ans;
    return 0;
}
相关推荐
I_belong_to_jesus9 小时前
C++关于分支预测的优化1
开发语言·c++·算法
Rabitebla10 小时前
【Linux】进程控制(十二) 自定义 Shell(二):内建命令与进程工作目录管理
linux·c++·笔记·学习·bash
码客-ygluu16 小时前
一个通用游戏数据服务器
c++·架构
another heaven16 小时前
【C/C++ Ranges 是零开销抽象吗?拆开管道、惰性求值和编译期膨胀】
c语言·开发语言·c++
Code_Solitude16 小时前
C语言动态内存 + 柔性数组 + 数组名退化
c语言·算法·柔性数组
上海潭龙东海科技有限公司16 小时前
客运站管控之动态孪生技术方案(新增一屏管控模块
数据仓库·人工智能·算法·重构·动态规划
YLCHUP18 小时前
【思维&图论建模】题解:债权(debt)_图论_建模_思路转化_思维题目_C++算法竞赛
c++·笔记·算法·数学建模·贪心算法·深度优先·图论
xiaoye-duck18 小时前
《C++ 项目:手写大模型接入 SDK》会话模块整合:内存 SessionManager 与 DataManager 持久化联动
开发语言·数据库·c++·语言模型
思麟呀19 小时前
背包DP(01背包+完全背包)
c++·算法