AcWing 105. 七夕祭—数学推导、贪心

6 篇文章 0 订阅
3 篇文章 0 订阅
文章介绍了如何解决AcWing105题——七夕祭的问题,即如何通过最小次数的交换使得摊位在行和列上均匀分布。通过分析得出,问题可以转换为行和列上的环型均分纸牌问题,然后利用数学推导和贪心算法来确定最少交换次数。最后给出C++代码实现求解行和列的最小交换次数。
摘要由CSDN通过智能技术生成

问题链接 AcWing 105. 七夕祭
问题描述
在这里插入图片描述
分析
首先,如果想要做到每行的摊位数都一样,那么总摊位数一定是行数的倍数(0倍也行),同理如果想要做到每列的摊位数都一样,那么总摊位数应该是列数的倍数。

其次,我们可以发现,我们在行上调整某个摊位,不会影响该摊位所在列的摊位数量,比如摊位 x 的位置为(x,y),上下调整到(x+1,y)、(x-1,y)不会影响对这一列的摊位数量有影响,同理我们在列上调整某个摊位,不会影响该摊位所在行的摊位数量。所以我们的目标最小的交换次数就等于最小在行上面的交换次数+最小在列上面的交换次数。这样就把问题拆分了。

可以发现,在行/列上,这是一道环型均分纸牌问题,这样就很好解决了。下面进行数学推导:
在这里插入图片描述
(这里分析行,列也是如此): 假设有n行,用集合{ a 1 , a 2 , . . . . , a n a_1,a_2,....,a_n a1,a2,....,an}表示,每行最终状态=avg= ∑ i = 1 n a i n \frac{\sum\limits_{i=1}^{n}a_i}{n} ni=1nai,avg可以直接算出来。那么我们根据上图可得,每个数都能从上一个数获得值,也能将自己的值传递给下一个数,最终达到avg,所以有:
a 1 + x 2 − x 1 = a v g a 2 + x 3 − x 2 = a v g a 3 + x 4 − x 3 = a v g . . . . . a n − 2 + x n − 1 − x n − 2 = a v g a n − 1 + x n − x n − 1 = a v g a n + x 1 − x n = a v g a_1+x_2-x_1=avg\\ a_2+x_3-x_2=avg\\ a_3+x_4-x_3=avg\\ .....\\ a_{n-2}+x_{n-1}-x_{n-2}=avg\\ a_{n-1}+x_{n}-x_{n-1}=avg\\ a_n+x_1-x_n=avg a1+x2x1=avga2+x3x2=avga3+x4x3=avg.....an2+xn1xn2=avgan1+xnxn1=avgan+x1xn=avg
做变形,将 a i a_i ai移到等式右边,可得:
x 2 − x 1 = a v g − a 1 x 3 − x 2 = a v g − a 2 x 4 − x 3 = a v g − a 3 . . . . . x n − 1 − x n − 2 = a v g − a n − 2 x n − x n − 1 = a v g − a n − 1 x 1 − x n = a v g − a n x_2-x_1=avg-a_1\\ x_3-x_2=avg-a_2\\ x_4-x_3=avg-a_3\\ .....\\ x_{n-1}-x_{n-2}=avg-a_{n-2}\\ x_{n}-x_{n-1}=avg-a_{n-1}\\ x_1-x_n=avg-a_n x2x1=avga1x3x2=avga2x4x3=avga3.....xn1xn2=avgan2xnxn1=avgan1x1xn=avgan
从下往上做累加,可得:
x 1 − x 1 = n ∗ a v g − { a n + a n − 1 + . . . . + a 3 + a 2 + a 1 } = 0 x 1 − x 2 = ( n − 1 ) ∗ a v g − { a n + a n − 1 + . . . . + a 3 + a 2 } x 1 − x 3 = ( n − 2 ) ∗ a v g − { a n + a n − 1 + . . . . + a 3 } . . . . . x 1 − x n − 2 = 3 ∗ a v g − { a n + a n − 1 + a n − 2 } x 1 − x n − 1 = 2 ∗ a v g − { a n + a n − 1 } x 1 − x n = a v g − a n x_1-x_1=n*avg-\{a_n+a_{n-1}+....+a_3+a_2+a_1\}=0\\ x_1-x_2=(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\}\\ x_1-x_3=(n-2)*avg-\{a_n+a_{n-1}+....+a_3\}\\ .....\\ x_{1}-x_{n-2}=3*avg-\{a_n+a_{n-1}+a_{n-2}\}\\ x_{1}-x_{n-1}=2*avg-\{a_n+a_{n-1}\}\\ x_1-x_n=avg-a_n x1x1=navg{an+an1+....+a3+a2+a1}=0x1x2=(n1)avg{an+an1+....+a3+a2}x1x3=(n2)avg{an+an1+....+a3}.....x1xn2=3avg{an+an1+an2}x1xn1=2avg{an+an1}x1xn=avgan
再次变形,将 x 1 x_1 x1挪到等式右侧:
x 1 = x 1 − { n ∗ a v g − { a n + a n − 1 + . . . . + a 3 + a 2 + a 1 } } = x 1 − 0 x 2 = x 1 − { ( n − 1 ) ∗ a v g − { a n + a n − 1 + . . . . + a 3 + a 2 } } x 3 = x 1 − { ( n − 2 ) ∗ a v g − { a n + a n − 1 + . . . . + a 3 } } . . . . . x n − 2 = x 1 − { 3 ∗ a v g − { a n + a n − 1 + a n − 2 } } x n − 1 = x 1 − { 2 ∗ a v g − { a n + a n − 1 } } x n = x 1 − { a v g − a n } x_1=x_1-\{n*avg-\{a_n+a_{n-1}+....+a_3+a_2+a_1\}\}=x_1-0\\ x_2=x_1-\{(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\}\}\\ x_3=x_1-\{(n-2)*avg-\{a_n+a_{n-1}+....+a_3\}\}\\ .....\\ x_{n-2}=x_{1}-\{3*avg-\{a_n+a_{n-1}+a_{n-2}\}\}\\ x_{n-1}=x_{1}-\{2*avg-\{a_n+a_{n-1}\}\}\\ x_n=x_1-\{avg-a_n\} x1=x1{navg{an+an1+....+a3+a2+a1}}=x10x2=x1{(n1)avg{an+an1+....+a3+a2}}x3=x1{(n2)avg{an+an1+....+a3}}.....xn2=x1{3avg{an+an1+an2}}xn1=x1{2avg{an+an1}}xn=x1{avgan}
我们的目标是 min ⁡ { ∣ x 1 ∣ + ∣ x 2 ∣ + . . . . + ∣ x n ∣ } \min\{|x_1|+|x_2|+....+|x_n|\} min{x1+x2+....+xn},按照上式子,
可以转化成最小化 min ⁡ { ∣ x 1 − 0 ∣ + ∣ x 1 − { ( n − 1 ) ∗ a v g − { a n + a n − 1 + . . . . + a 3 + a 2 } } ∣ } + . . . . + ∣ x 1 − { 2 ∗ a v g − { a n + a n − 1 } } ∣ + ∣ x 1 − { a v g − a n } ∣ \min\{|x_1-0|+|x1-\{(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\}\}|\}+....+|x_1-\{2*avg-\{a_n+a_{n-1}\}\}|+|x_1-\{avg-a_n\}| min{x10∣+x1{(n1)avg{an+an1+....+a3+a2}}}+....+x1{2avg{an+an1}}+x1{avgan}

这个式子的含义就是 x 1 x_1 x1到点 { 0 , ( n − 1 ) ∗ a v g − { a n + a n − 1 + . . . . + a 3 + a 2 } , ( n − 2 ) ∗ a v g − { a n + a n − 1 + . . . . + a 3 } , . . . , 2 ∗ a v g − { a n + a n − 1 } , a v g − a n } \{0,(n-1)*avg-\{a_n+a_{n-1}+....+a_3+a_2\},(n-2)*avg-\{a_n+a_{n-1}+....+a_3\},...,2*avg-\{a_n+a_{n-1}\},avg-a_n\} {0,(n1)avg{an+an1+....+a3+a2},(n2)avg{an+an1+....+a3},...,2avg{an+an1},avgan}的距离,那么这就是一个区间选址的贪心问题, x 1 x_1 x1的值选在这些点的中间位置即可。
代码如下

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+10;

int r[N],c[N];//存原始数据
int c_r[N],c_c[N];

int main(){
    int n,m,t;
    ll row=-1,column=-1;
    cin>>n>>m>>t;
    for(int i=0;i<t;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        r[x]++;
        c[y]++;
    }
    int avg;
    if(t%n==0){
        row=0;
        avg=t/n;
        int res=0;
        for(int i=1;i<=n;i++){
            res+=avg-r[n-i+1];
            c_r[i]=res;
        }
        sort(c_r+1,c_r+n+1);
        for(int i=1;i<=n;i++)
            row+=abs(c_r[(n+1)>>1]-c_r[i]);
    }
    if(t%m==0){
        column=0;
        avg=t/m;
        int res=0;
        for(int i=1;i<=m;i++){
            res+=avg-c[m-i+1];
            c_c[i]=res;
        }
        sort(c_c+1,c_c+m+1);
        for(int i=1;i<=m;i++)
            column+=abs(c_c[(m+1)>>1]-c_c[i]);
    }
    if(row==-1&&column==-1) puts("impossible");
    else if(row>=0&&column>=0) cout<<"both "<<row+column<<endl;
    else if(row>=0)  cout<<"row "<<row<<endl;
    else cout<<"column "<<column<<endl;
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chp的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值