PIPIOJ 1018: 士兵排阵 贪心 数学

http://pipioj.online/problem.php?id=1018
在这里插入图片描述
思路:和这道题很像。既然已知当 x = a [ m i d ] x=a[mid] x=a[mid]时, ∑ i = 1 n ∣ a i − x ∣ \sum_{i=1}^n|a_i-x| i=1naix取得最小值,那么将所有士兵移动到同一行的纵坐标就确定了。现在考虑横坐标,假设最终结果中第一个士兵的横坐标为 t t t,那么根据贪心策略,我们肯定希望最小的 x i x_i xi移动到 t t t,第二小的 x i x_i xi移动到 t + 1 t+1 t+1……那么对横坐标进行排序后,我们希望求出:
m i n ( ∑ i = 1 n ∣ x i − ( t + i − 1 ) ∣ ) = m i n ( ∑ i = 1 n ∣ ( x i − i + 1 ) − t ∣ ) min(\sum_{i=1}^n|x_i-(t+i-1)|)=min(\sum_{i=1}^n|(x_i-i+1)-t|) min(i=1nxi(t+i1))=min(i=1n(xii+1)t)
x i ′ = x i − i + 1 x_i'=x_i-i+1 xi=xii+1,上式可变为: m i n ( ∑ i = 1 n ∣ x i ′ − t ∣ ) min(\sum_{i=1}^n|x_i'-t|) min(i=1nxit),显然当 t = x ′ [ m i d ] t=x'[mid] t=x[mid]时取得最小值。

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

const int maxn=1e4+5;

int n,x[maxn],y[maxn];

int main()
{
    
    
    while(~scanf("%d",&n))
    {
    
    
        for(int i=1;i<=n;i++)
            scanf("%d %d",&x[i],&y[i]);
        sort(x+1,x+1+n);
        for(int i=1;i<=n;i++)
            x[i]-=i-1;
        sort(x+1,x+1+n);
        sort(y+1,y+1+n);
        int xmid=x[(n+1)>>1];
        int ymid=y[(n+1)>>1];
        int cnt=0;
        for(int i=1;i<=n;i++)
            cnt+=abs(x[i]-xmid)+abs(y[i]-ymid);
        printf("%d\n",cnt);
    }
    return 0;
}

猜你喜欢

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