X轴上有N个点,每个点除了包括一个位置数据X[i],还包括一个权值W[i]。该点到其他点的带权距离 = 实际距离 * 权值。求X轴上一点使它到这N个点的带权距离之和最小,输出这个最小的带权距离之和。
Input
第1行:点的数量N。(2 <= N <= 10000) 第2 - N + 1行:每行2个数,中间用空格分隔,分别是点的位置及权值。(-10^5 <= X[i] <= 10^5,1 <= W[i] <= 10^5)
Output
输出最小的带权距离之和。
Input示例
5 -1 1 -3 1 0 1 7 1 9 1
Output示例
20
解题思路:对于本题我们需要确定的一点是最优的点的位置肯定是这个N个点中其中的一个,我们可以利用反证法来证明我们的猜想是正确的。
假设我们的最优解在第j和第j+1个顶点之间,则左边存在j-1个顶点,右边存在n-j-1个顶点,我们分下面三种情况讨论:
(1)j-1=n-j-1时,我们将最优点放到第j个点或者第j+1个点得到的最终结果都要比放在j和j+1之间要优
(2)j-1>n-j-1时,我们将最优点放在第j个点要比放在j和j+1之间更优
(3)j-1<n-j-1时,我们将最优点放在第j+1点要比放在j和j+1之间更优。
上面的东西搞明白了,我们便可以dp了,dp[i]表示以i为放置点得到的结果,然后ans = min(dp[i]) (1<=i<=n)
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <string> #include <vector> #include <map> #include <set> #include <algorithm> #include <functional> using namespace std; typedef long long ll; const int maxn = 10010; struct Point { int x, w; Point() { } Point(int t_x, int t_w) : x(t_x), w(t_w) { } bool operator < (const Point &p) const { return x < p.x; } }point[maxn]; ll dp1[maxn], dp2[maxn], dp[maxn]; ll sumw1[maxn], sumw2[maxn]; int main() { //freopen("aa.in", "r", stdin); ll ans; int n; scanf("%d", &n); for(int i = 1; i <= n; ++i) { scanf("%d %d", &point[i].x, &point[i].w); } sort(point + 1, point + n + 1); sumw1[0] = 0; dp1[1] = 0; for(int i = 1; i <= n; ++i) { if(i > 1) { dp1[i] = dp1[i-1] + sumw1[i-1] * (point[i].x - point[i-1].x); } sumw1[i] = sumw1[i-1] + point[i].w; } sumw2[n+1] = 0; dp2[n] = 0; for(int i = n; i >= 1; --i) { if(i < n) { dp2[i] = dp2[i+1] + sumw2[i+1] * (point[i+1].x - point[i].x); } sumw2[i] = sumw2[i+1] + point[i].w; } dp[1] = dp1[1] + dp2[1]; ans = dp[1]; for(int i = 2; i <= n; ++i) { dp[i] = dp1[i] + dp2[i]; if(dp[i] < ans) { ans = dp[i]; } } printf("%lld\n", ans); return 0; }
另外本题还有其余的解法,参考博客:http://blog.csdn.net/zhang20072844/article/details/13372753
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <string> #include <vector> #include <map> #include <set> #include <algorithm> #include <functional> using namespace std; typedef long long ll; const int maxn = 10010; struct Point { int x, w; Point() { } Point(int t_x, int t_w) : x(t_x), w(t_w) { } bool operator < (const Point &p) const { return x < p.x; } }point[maxn]; int main() { int n; int pos; ll sumw = 0, tw = 0, ans = 0; scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%d %d", &point[i].x, &point[i].w); sumw += point[i].w; } sort(point, point + n); for(int i = 0; i < n; ++i) { tw += point[i].w; if(tw >= sumw/2) { pos = i; break; } } for(int i = 0; i < n; ++i) { if(i < pos) { ans += 1LL * (point[pos].x - point[i].x) * point[i].w; } else if(pos < i) { ans += 1LL * (point[i].x - point[pos].x) * point[i].w; } } printf("%lld\n", ans); return 0; }