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;
}
题目要求输出行和列需要经过增氧的变换 可以使行列之和相等
换句话说 如果把行列数先求出来 对于行数 单独按照上一题的思路进行变换
对于列数 单独按照上一题的思路进行变换
最后统计一下 行列交换的结果 就行
代码如下 写的有些乱 不太好看懂
#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;
}