PIPIOJ 1413: 士兵排阵Ⅲ 带权中位数问题

http://pipioj.online/problem.php?id=1413
在这里插入图片描述
思路:带权中位数问题,详细证明参见百度百科。先给出结论: ∑ i = 1 n ∣ x i − x ∣ ∗ w i \sum_{i=1}^{n}|x_i-x|*w_i i=1nxixwi的最小值当且仅当 x = x ( ∑ i = 1 n w i ) / 2 x=x_{(\sum_{i=1}^nw_i)/2} x=x(i=1nwi)/2(此处不细致考虑下标问题)时取得。这里给出我自己的理解(非严谨证明),我们知道 ∑ i = 1 n ∣ x i − x ∣ \sum_{i=1}^{n}|x_i-x| i=1nxix的最小值当且仅当 x = x n / 2 x=x_{n/2} x=xn/2(即x等于中位数时)取得,那么对于上面的式子,我们可以把数列从 n n n项扩展到 ∑ i = 1 n w i \sum_{i=1}^nw_i i=1nwi项,这样就可以把权值消去,问题转换成了普通的中位数问题,结论依然成立。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
using ll=long long;

const int maxn=1e5+5;

struct node
{
    
    
    int x,y,w;
    node(int x=0,int y=0,int w=0):x(x),y(y),w(w){
    
    }
};

int n;
node a[maxn];

int main()
{
    
    
    scanf("%d",&n);
    int num=0;
    for(int i=1;i<=n;i++)
        scanf("%d %d %d",&a[i].x,&a[i].y,&a[i].w),num+=a[i].w;
    num=(num+1)>>1;
    sort(a+1,a+1+n,[](const node &a,const node &b){
    
     return a.x<b.x; });
    ll ans=0;
    int tmp=0,idx=0,mid;
    while(tmp<num)
        tmp+=a[++idx].w;
    mid=a[idx].x;
    for(int i=1;i<=n;i++)
        ans+=(ll)abs(a[i].x-mid)*a[i].w;
    sort(a+1,a+1+n,[](const node &a,const node &b){
    
     return a.y<b.y; });
    tmp=idx=0;
    while(tmp<num)
        tmp+=a[++idx].w;
    mid=a[idx].y;
    for(int i=1;i<=n;i++)
        ans+=(ll)abs(a[i].y-mid)*a[i].w;
    printf("%lld\n",ans);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/xiji333/article/details/114448408