uva11300 + uvalive5809 中位数

来源:互联网 发布:有线网络电视怎么连接 编辑:程序博客网 时间:2024/06/09 20:07

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;}


0 0
原创粉丝点击