航海题解

航海

https://www.nowcoder.com/questionTerminal/1ac46a9b79194cb987c0579dfdf3121a

首先来看一个简化版的问题,一条线上有个点,为了把所有点移到一起,怎么移动花费最小?
假设我们现在选取了一个位置,它左边及处有个点,右边有个点,现在总花费为。我们现在让右移一个单位,记为,那么很明显处的花费变成了,可以发现从左到右花费是先减少再增大的,不难得知这是一个单峰函数,且在的时候取得最值,其实这也是中位数的一个应用。那么解决这个简化版的问题就可以去找中位数来求解。
对于本题来说还有两个问题没解决。
首先是权值,其实权值可以看成有个点在这个位置,并且继续用上述得到的性质就好了。
最后还有一个问题就是本题是二维的。虽然本题是二维,但是细想可以发现,因为是曼哈顿距离,所以是互不影响的,分别对求一次答案加起来就好了,注意要用 噢。
本题时间复杂度,空间复杂度
中位数代码:

struct node {
    long long x,y,w;
}a[110000];
bool cmp1(node a,node b) {
    return a.x<b.x;
}
bool cmp2(node a,node b) {
    return a.y<b.y;
}
class Solution {
public:
    /**
     * 
     * @param n int整型 n
     * @param x int整型一维数组 x
     * @param xLen int x数组长度
     * @param y int整型一维数组 y
     * @param yLen int y数组长度
     * @param w int整型一维数组 w
     * @param wLen int w数组长度
     * @return long长整型
     */
    long long MinimumDistance(int n, int* x, int xLen, int* y, int yLen, int* w, int wLen) {
        // write code here
        long long sum=0,ans=0;
        for(int i=1;i<=n;i++) {
            a[i].x=x[i-1];
            a[i].y=y[i-1];
            a[i].w=w[i-1];
            sum+=a[i].w;
        }
        sum>>=1;
        sort(a+1,a+1+n,cmp1);//按照x排序
        long long tmp=0,ch;
        for(int i=1;i<=n;i++) {//找中位数位置
            tmp+=a[i].w;
            if(tmp>sum) {
                ch=a[i].x;
                break;
            }
        }
        for(int i=1;i<=n;i++)
            ans+=abs(a[i].x-ch)*a[i].w;
        //y
        sort(a+1,a+1+n,cmp2);//按照y排序
        tmp=0;
        for(int i=1;i<=n;i++) {//找中位数位置
            tmp+=a[i].w;
            if(tmp>sum) {
                ch=a[i].y;
                break;
            }
        }
        for(int i=1;i<=n;i++)
            ans+=abs(a[i].y-ch)*a[i].w;
        return ans;
    }
};

除了中位数的做法呢咋们可以依次枚举计算贡献。
假定现在我们已经按x排好序了分别是ABC三个点,那么C到AB的距离和是
C.w|C.x-A.x|+B.w|C.x-B.x|,又因为已经排序了,那么绝对值可以去掉,
得:A.w(C.x-A.x)+B.w(C.x-B.x)
化简得:
A.wC.x-A.wA.x+B.wC.x-B.w*B.x
C.x
(A.w+B.w)-(A.wA.x+B.w*B.x)
假设有四个点ABCD,计算D到ABC的距离
化简得:
D.x
(A.w+B.w+C.w)-(A.wA.x+B.wB.x+C.wC.x)
在计算过程中跟踪(A.w+B.w+C.w),代码中记做ww,
(A.w
A.x+B.wB.x+C.wC.x),代码中记做sum

class Solution {
public:
    struct node {
    long long x, y, w,sum1,sum2;
};
long long MinimumDistance(int n, int* x, int xLen, int* y, int yLen, int* w, int wLen) {
    // write code here
    typedef long long ll;
    vector<node>a(n);
    for (int i = 0; i < xLen; i++)
        a[i] = { x[i],y[i],w[i],0,0 };
    sort(a.begin(), a.end(), [](node& a, node& b) { return a.x < b.x; });
    ll sum=0,ww=0,sum1=0,ww1=0,ans=INT64_MAX;
    for (ll i = 0; i < n; i++) {
        a[i].sum1 += a[i].x*ww-sum;
        a[n-i-1].sum1 += sum1-a[n-i-1].x*ww1;
        sum += a[i].x*a[i].w;
        ww += a[i].w;
        sum1 += a[n-i-1].x*a[n-i-1].w;
        ww1 += a[n-i-1].w;
    }
    sort(a.begin(), a.end(), [](node& a, node& b) { return a.y < b.y; });
    sum=0,ww=0,sum1=0,ww1=0;
    for (int i = 0; i < n; i++) {
        a[i].sum2+=a[i].y*ww-sum;
        a[n-i-1].sum2+=sum1-a[n-i-1].y*ww1;
        sum+=a[i].y*a[i].w;
        ww+=a[i].w;
        sum1+=a[n-i-1].y*a[n-i-1].w;
        ww1+=a[n-i-1].w;
    }
    ll ch1=1e18,ch2=1e18;
    for(int i=0;i<n;i++) {
        ch1=min(ch1,a[i].sum1);
        ch2=min(ch2,a[i].sum2);
    }
    return ch1+ch2;
}
};
全部评论

相关推荐

点赞 评论 收藏
分享
10-21 23:48
蚌埠坦克学院
csgq:可能没hc了 昨天一面完秒挂
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务