这三个版本根据难易程度依次排序:
都是线段上一点到其余各点的距离和最小,或者是其变形。
1096 - 距离之和最小
这是个基础题,很明显,这个点应该选在中位数。依据是这个绝对值不等式 |x−p|+|y−p|≥|x−y| | x − p | + | y − p | ≥ | x − y | 。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main()
{
for (int n; EOF != scanf("%d", &n); ) {
vector<LL> points(n);
for (int i = 0; i < n; scanf("%lld", &points[i++])) {}
sort(points.begin(), points.end());
LL mid = points[n / 2];
printf("%lld\n", accumulate(points.begin(), points.end(), 0LL, [&mid] (LL ans, LL ele) {
return ans + abs(mid - ele);
}));
}
return 0;
}
1108 - 距离之和最小V2
求一个空间点到其余各点的曼哈顿距离的最小和。看起来好像和第一题很想啊,第一题选中位数,那么类比,这个空间点应该选在其余各点组成的凸立方体(凸体,类似凸包)的内部,没错,是的。
但是,好像这个点只是那么直观地可以确定啊,于是,我们换一个角度,空间曼哈顿距离的定义是 |x1−x2|+|y1−y2|+|z1−z2| | x 1 − x 2 | + | y 1 − y 2 | + | z 1 − z 2 | ,先不看 y,z y , z ,那么这个问题是不是又和上面一个问题一样了,而且 x x 是不会影响的,因此这个题只需要对 x,y,z x , y , z 做上面的算法就行了。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
LL solve(vector<LL> &points)
{
sort(points.begin(), points.end());
LL mid = points[points.size() / 2];
return accumulate(points.begin(), points.end(), 0LL, [&mid] (LL ans, LL ele) {
return ans + abs(mid - ele);
});
}
int main()
{
for (int n; EOF != scanf("%d", &n); ) {
vector<vector<LL> > arr(3, vector<LL>(n));
for (int i = 0; i < n; scanf("%lld%lld%lld",
&arr[0][i], &arr[1][i], &arr[2][i]), ++i) {}
LL ans = 0;
for (auto &v : arr)
ans += solve(v);
printf("%lld\n", ans);
}
return 0;
}
1110 - 距离之和最小V3
这个题初看起来不怎么好做,但是注意到题中的 W[i]>0 W [ i ] > 0 ;
这个题的关键就是拆点,把权值看成点数,也就是说有 W[i] W [ i ] 个点重合在 pos[i] p o s [ i ] ,这样子这个题是不是又回到了第一题!
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main()
{
for (int n; EOF != scanf("%d", &n); ) {
vector<pair<LL, LL> > arr(n);
for (int i = 0; i < n; scanf("%lld%lld", &arr[i].first, &arr[i].second), ++i) {}
sort(arr.begin(), arr.end());
LL sum = accumulate(arr.begin(), arr.end(), 0LL, [] (LL sum, pair<LL, LL> &ele) {
return sum + ele.second;
});
auto it = find_if(arr.begin(), arr.end(), [sum] (pair<LL, LL> &ele) {
static LL index = 0;
return (index += ele.second) > sum / 2;
});
printf("%lld\n", accumulate(arr.begin(), arr.end(), 0LL, [&it] (LL sum, pair<LL, LL> &ele) {
return sum + abs(ele.first - it->first) * ele.second;
}));
}
return 0;
}