贪心模型:环形纸牌分配
作者:互联网
分析
首先,我们可以分析出,在一行中,各列摊位之间交换位置,是不会改变行的摊位数量,列也同理
,则我们的问题就变为了,怎样移动可以获得最少移动次数,是的每行每列,其中各各格子的数都相同。
这时,就出现了一个贪心模型环形卡牌分配
题目默认只能左右传递,则,最优解一定是没有来回的,所从全局来看,传递关系,可以用一条线来表示。
为了让每个人的糖果一样多,那么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;
}
标签:纸牌,ai,环形,int,x2,x3,x1,x4,贪心 来源: https://www.cnblogs.com/aitejiu/p/15171332.html