uva11300 + uvalive5809 中位数

uva11300 的基本思想是利用中位数的性质

x1表示的是第一个人需要给第四个人多少金币

x2表示的是第二个人需要给第一个人多少金币

x3表示的是第三个人需要给第一个人多少金币

.....

xn-1表示的是第n-1个人需要给第一个人多少金币


对于一开始每个人的金币数用Ai表示 

M表示最终每个人得到的金币数  M = 金币总数 / 总人数

对于第一个人A1 - x1 + x2 = M - A1 + x1 = x1 - C1

对于第一个人A2 - x2 + x3 = M - A2 + x2 = x1 -  C2

对于第一个人A3 - x3 + x4 = M - A3 + x3 = x1 -  C3

其中 Cn = (A1 + A2 + …… + An) - n*M = An + C(n-1) - M


要求最小的交换次数 就转换为了 求  |x1| + |x1 - C1| + |x2 - C2| + …… + |x1 - C(n-1)|


几何意义就是数轴上的点C1、C2、C3、……、C(n-1)  到x1点的距离的最小值


有中位数的一个性质:在给定的数轴上的 n 个点, 在数轴上的所有点中, 中位数离所有顶点的距离之和最小。 证明略 )


下面给出代码:

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;

const int maxn = 1000000+10;
long long a[maxn], c[maxn], tot, m;
int main()
{
    int n;
    while(scanf("%d",&n) == 1)
    {
        tot = 0;
        for(int i = 1; i <= n; i++)
        {
            scanf("%lld",&a[i]);
            tot += a[i];
        }
        m = tot / n;     //确定最终每个人得到的金币的数量
        c[0] = 0;
        for(int i = 0; i < n; i++)
            c[i] = c[i-1] + a[i] - m;
        sort(c, c + n);
        long long x1 = c[n/2];  //求出c[n]数组中的中位数
        long long ans = 0;
        for(int i = 0; i < n; i++)
            ans += abs(x1 - c[i]);
        printf("%lld\n",ans);
    }
    return 0;
}


而对于uvalive5809是对 上一题的变形


题目要求输出行和列需要经过增氧的变换 可以使行列之和相等

换句话说 如果把行列数先求出来 对于行数 单独按照上一题的思路进行变换 

                                                          对于列数 单独按照上一题的思路进行变换 

最后统计一下 行列交换的结果 就行


代码如下 写的有些乱 不太好看懂

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;

const int maxn = 1000+10;
long long a[maxn], c[maxn], tot, m;
int yuanshi[maxn][maxn];
char shuru[maxn][maxn];

int change(int a[], int n)
{
    tot = 0;
    for(int i = 1; i <= n; i++)
        tot += a[i];
    
    if(tot % n != 0)
        return -1;   //一定不会交换成功
    m = tot / n;     //确定最终每个人得到的金币的数量
    c[0] = 0;
    for(int i = 0; i < n; i++)
        c[i] = c[i-1] + a[i] - m;
    sort(c, c + n);
    long long x1 = c[n/2];  //求出c[n]数组中的中位数
    long long ans = 0;
    for(int i = 0; i < n; i++)
        ans += abs(x1 - c[i]);
    return ans;   //成功
}

int main()
{
    int n;
    int time1;
    int row1,column1;
    int rowjieguo, columnjieguo;
    int row[maxn],column[maxn];
    scanf("%d\n",&time1);
    for(int i = 1; i <= time1; i++)
    {
        memset(shuru, '\0', sizeof(shuru));
        memset(yuanshi, 0, sizeof(yuanshi));
        scanf("%d%d",&row1,&column1);
        
        for(int i1 = 1; i1 <= row1; i1++)
            scanf("%s",shuru[i1]);                           //输入

        for(int i1 = 1; i1 <= row1; i1++)
        {
            for(int j1 = 1; j1 <= column1; j1++)
                yuanshi[i1][j1] = (int)shuru[i1][j1-1]-30-18;
        }                                                      //对输入的结果进行转换
     
        memset(row, 0, sizeof(row));
        memset(column, 0, sizeof(column));
        rowjieguo = columnjieguo = 0;
        //初始化
        for(int i1 = 1; i1 <= row1; i1++)
        {
            for(int j1 = 1; j1 <= column1; j1++)
                row[i1] += yuanshi[i1][j1];
        }
        rowjieguo = change(row, row1);


        for(int j1 = 1; j1 <= column1; j1++)
        {
            for(int i1 = 1; i1 <= row1; i1++)
                column[j1] += yuanshi[i1][j1];
        }
        columnjieguo = change(column, column1);

        //结果输出
        if(rowjieguo == -1 && columnjieguo == -1)
            printf("Case %d: impossible\n",i);

        if(rowjieguo == -1 && columnjieguo != -1)
            printf("Case %d: column %d\n",i, columnjieguo);

        if(rowjieguo != -1 && columnjieguo == -1)
            printf("Case %d: row %d\n",i, rowjieguo);

        if(rowjieguo != -1 && columnjieguo != -1)
            printf("Case %d: both %d\n",i, rowjieguo+columnjieguo);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/Han_DV/article/details/47358367
今日推荐