贪心模型:环形纸牌分配

原题链接

分析

首先,我们可以分析出,在一行中,各列摊位之间交换位置,是不会改变行的摊位数量,列也同理,则我们的问题就变为了,怎样移动可以获得最少移动次数,是的每行每列,其中各各格子的数都相同。

这时,就出现了一个贪心模型环形卡牌分配

题目默认只能左右传递,则,最优解一定是没有来回的,所从全局来看,传递关系,可以用一条线来表示。

贪心模型:环形纸牌分配

为了让每个人的糖果一样多,那么x1,x2,x3......的取值就是这样

设平均值为ai,设x1为*变量,将xi全部用x1表示

x1 = x1 x1 = x1 - 0

x2 = a[2] + x1 -ai x2 = x1 - (ai-a[2])

x3 = a[3] + x2 -ai => x3 = x1 -(2*ai - a[2] - a[3])

x4 = a[4] + x3 -ai x4 = x1 - (3*ai - a[2] - a[3] - a[4])

x5 = a[5] + x4 -ai x5 = x1 - (4*ai - a[2] - a[3] - a[4] - a[5])

要使传递糖果的代价最小,则是另

\[|x_1| + |x_2| + |x_3| + ...... + |x_5| \]

和最小,即

\[|x_1|+|x_1-(a_i-a[2])|+|x_1-(2*a_i-a[2]-a[3])|+......+|x_1-(4*a_i)-a[2|-a[3]-a[4]-a[5]| \]

最小,则这题就与货仓选址问题相同了,只需要取这些数中的中位数,即可取到最小值。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+10;
int row[N],col[N],s[N],c[N];
int n,m,k;

LL work(int n,int a[])
{
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    
    if(s[n]%n) return -1;
    
    LL avg = s[n]/n;
    
    c[1]=0;
    for(int i=2;i<=n;i++) c[i]=s[i-1] - (i-1)*avg;
    
    sort(c+1,c+n+1);
    LL res = 0;
    for(int i=1;i<=n;i++) res+=abs(c[i]-c[(n+1)/2]);
    
    return res;
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    while(k--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        row[a]++,col[b]++;
    }
    
    LL r = work(n,row);
    LL c = work(m,col);
    
    if(r!=-1&&c!=-1) printf("both %lld\n",c+r);
    else if(r!=-1) printf("row %lld\n",r);
    else if(c!=-1) printf("column %lld\n",c);
    else puts("impossible");
    return 0;
}
上一篇:R 基本数据管理(1)


下一篇:在canvas中绘制箭头