题解 -NOIp2013 Day1T3 货车运输(truck.cpp/.c/.pas)

博客详细介绍了NOIp2013 Day1T3的货车运输问题,讲解了如何利用Kruskal算法构建最大生成树,以及使用LCA求最近公共祖先来找到货车的最大载重路径。内容包括题目描述、主要思路、算法详解和样例分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

-NOIp2013 Day1T3 货车运输(truck.cpp/.c/.pas)

欢迎来到本蒟蒻的题解

题目

货车运输 (truck.cpp/c/pas)
题目描述 Description
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q
辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入描述 Input Description
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
输出描述 Output Description
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
样例输入 Sample Input
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
样例输出 Sample Output
3
-1
3
数据范围及提示 Data Size & Hint
对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。


主要思路(大致方向)

这一题是Noip2013Day1的压轴题,必定有它的难度(提高+/省选-)
这是一道大算法题(并查集,kruskal最大生成树,倍增,lca最近公共祖先,深搜) 骗小部分分的暴力算法就不说了,下面来谈一谈正解
做这道题的步骤:
Step(1):Kruskal生成最大生成树
Step(2):lca求最近公共祖先
Step(3):在连接两个点的n条路径里面找最小,即正确答案


本题算法

由于本题算法较多,在这里给大家把相关的链接奉上

数据结构–并查集的原理及实现—— [ hapjin博客园 ]

最小生成树之Kruskal算法—— [ Enstein_Jun 优快云博客 ]

白话系列 倍增算法—— [ jarjingx 优快云博客 ]

LCA 最近公共祖先—— [ Angel_Kitty 博客园 ]

深度优先搜索的实现—— [ 神奕 优快云博客 ]


为什么要用KrusKal求最大生成树

如图,点1至点2可能存在有多条路径,我们为了要找到最大的限重,就一定会选择限重最大的那一条边,而不会去选择另外限重极小的边
所以这个时候,我们就需要对Kruskal最小生成树算法改写排序规则使其成为最大生成树,两个点之间只保留一条最大限重边
处理过后原本m条边就降到了n-1条边,对空间和时间都有优化

<think>题目要求我们使用中文回答问题,并在回答后提出3-5个相关问题,且第一行必须完整输出“§§相关问题§§”,然后紧接着列出问题,禁止换行分散。 首先,我需要理解用户给出的问题:用户提供了一个洛谷题目的链接(P1452),要求提供C++题解。因此,我的任务是编写解决这个题目的C++代码,并解释思路。 题目链接:https://www.luogu.com.cn/problem/P1452 题目名称:Beauty Contest(旋转卡壳求凸包直径) 题目大意:给定平面上的一些点,求最远点对的距离的平方。 解题思路: 1. 求凸包:使用Andrew算法或Graham扫描法求凸包。 2. 旋转卡壳:在凸包上求直径(最远点对)。 步骤: 1. 读入点集。 2. 对点集进行排序(按x从小到大,x相同则按y从小到大)。 3. 求凸包(下凸包和上凸包)。 4. 使用旋转卡壳算法在凸包上寻找距离最远的两个点。 5. 输出距离的平方。 注意:题目要求输出距离的平方(避免浮点数运算,但本题输入是整数,所以平方也是整数)。 代码实现: - 凸包求法:使用Andrew算法。 - 旋转卡壳:使用双指针法,遍历凸包上的点,利用叉积和点积的性质。 现在,编写C++代码,并添加必要的注释。 代码完成后,按照要求提出3-5个相关问题。 相关问题应该与题目相关,例如凸包、旋转卡壳、计算几何的基础知识等。 下面开始编写代码:</think>### 洛谷 P1452 "Beauty Contest" C++ 题解 **题目大意**:给定平面上的 $n$ 个点,求最远点对距离的平方($1 \leq n \leq 5 \times 10^4$)。 **核心算法**:Andrew 凸包算法 + 旋转卡壳求直径 **代码实现**: ```cpp #include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; struct Point { ll x, y; Point(ll x = 0, ll y = 0) : x(x), y(y) {} bool operator<(const Point &p) const { return x < p.x || (x == p.x && y < p.y); } Point operator-(const Point &p) const { return Point(x - p.x, y - p.y); } }; // 叉积 ll cross(const Point &a, const Point &b) { return a.x * b.y - a.y * b.x; } // 距离平方 ll dist2(const Point &a, const Point &b) { ll dx = a.x - b.x, dy = a.y - b.y; return dx * dx + dy * dy; } // 求凸包(Andrew算法) vector<Point> convexHull(vector<Point> &p) { int n = p.size(), k = 0; if (n <= 1) return p; vector<Point> hull(2 * n); sort(p.begin(), p.end()); // 下凸包 for (int i = 0; i < n; hull[k++] = p[i++]) while (k >= 2 && cross(hull[k-1]-hull[k-2], p[i]-hull[k-2]) <= 0) k--; // 上凸包 for (int i = n-2, t = k+1; i >= 0; hull[k++] = p[i--]) while (k >= t && cross(hull[k-1]-hull[k-2], p[i]-hull[k-2]) <= 0) k--; hull.resize(k - 1); return hull; } // 旋转卡壳求凸包直径平方 ll rotatingCalipers(vector<Point> &hull) { int n = hull.size(); if (n == 1) return 0; if (n == 2) return dist2(hull[0], hull[1]); ll ans = 0; for (int i = 0, j = 1; i < n; ++i) { // 移动对踵点直到距离不再增加 while (abs(cross(hull[(i+1)%n]-hull[i], hull[j]-hull[i])) < abs(cross(hull[(i+1)%n]-hull[i], hull[(j+1)%n]-hull[i]))) { j = (j + 1) % n; } ans = max(ans, dist2(hull[i], hull[j])); } return ans; } int main() { int n; cin >> n; vector<Point> p(n); for (int i = 0; i < n; ++i) cin >> p[i].x >> p[i].y; vector<Point> hull = convexHull(p); cout << rotatingCalipers(hull) << endl; return 0; } ``` **算法解析**: 1. **凸包构建**(Andrew 算法) - 排序点集后,分别计算下凸包和上凸包 - 利用叉积判断点的走向($\leq 0$ 保留共线点) 2. **旋转卡壳求直径** - 对凸包上的点,用双指针 $i$ 和 $j$ 遍历 - 关键优化:当 $j$ 移动到使三角形面积(叉积绝对值)最大时,更新最远距离 - 时间复杂度:$O(n)$(凸包 $O(n \log n)$,卡壳 $O(n)$)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值