《算法竞赛进阶指南》七夕祭

 链接:http://exam.upc.edu.cn/problem.php?cid=1430&pid=12

题意:

给定 n*m 矩阵中 T 个点的坐标,判断通过移动相邻坐标后,是否能使每行(每列)拥有的点数都相等,并输出最小移动步数。

第1和n也看作是相邻的。

思路:

见下方糖果传递链接。

相关问题:糖果传递问题,n个同学

参考:

https://www.cnblogs.com/CtrlCV/p/5626194.html

https://blog.csdn.net/moep0/article/details/52506765

代码:

#include 
#define LL long long
using namespace std;
const int maxn = 1e5+5;

LL t, n, m, x[maxn], y[maxn], s1[maxn], s2[maxn];
void solve()
{
    LL ans = 0, sum = 0;
    if(t%n==0){
        for(int i=1; i<=n; ++i) sum += x[i];
        int average = sum/n;
        for(int i=1; i<=n; ++i) x[i] -= average;
        for(int i=1; i<=n; ++i) s1[i] = s1[i-1]+x[i];
        sort(s1+1, s1+n+1);
        average = s1[(n+1)/2];
        for(int i=1; i<=n; ++i) ans += abs(average-s1[i]);
    }
    sum = 0;
    if(t%m==0){
        for(int i=1; i<=m; ++i) sum += y[i];
        int average = sum/m;
        for(int i=1; i<=m; ++i) y[i] -= average;
        for(int i=1; i<=m; ++i) s2[i] = s2[i-1]+y[i];
        sort(s2+1, s2+m+1);
        average = s2[(m+1)/2];
        for(int i=1; i<=m; ++i) ans += abs(average-s2[i]);
    }
    printf("%lld\n", ans);
}
int main()
{
    int a, b;
    scanf("%lld%lld%lld", &n, &m, &t);
    for(int i=1; i<=t; ++i)
        scanf("%d%d", &a, &b), x[a]++, y[b]++;
    if(t%n!=0&&t%m!=0){
        printf("impossible\n");
        return 0;
    }
    if(t%n==0&&t%m==0) printf("both ");
    else if(t%n==0) printf("row ");
    else if(t%m==0) printf("column ");
    solve();
}
/***
2 8 8
1 1
1 2
1 3
1 4
1 5
1 6
1 7
1 8
*/

 

你可能感兴趣的:(水题)