Mine Layer(2008 World Final C)

Mine Layer(2008 World Final C)

题意

类似于扫雷游戏,在一些格子中散布着一些地雷,具体的埋藏位置并不清楚,但知道每个格子及其周围八个格子的地雷总数。请问此时正中间那一行最多可能有多少地雷(题目假定所有的输入都是奇数行的)?
在这里插入图片描述

输入:

第一行,有一个正整数N,代表有N个测试数据。

每个测试数据的第一行包含两个正整数R(行数,R是奇数)和C(列数)。以下是R行每行C列的正整数。

输出:

每个测试数据输出一行,“Case #X: Y”,x为第几个测试数据,Y为正中间那一行最多可能有的地雷数。

限制条件

输入有R行C列

3≤R≤49,R是奇数

3≤C≤49

预备内容

我们先考虑一维的情况。

题意

每个格子内有一个数字,具体数字不详,但是知道这个格子和左右两个相邻格子内的数字之和,求问正中间的格子中的数字最大值。


粗略考虑肯定是个搜索(范围到49必然会爆T)或者dp,但是其实是个规律题。

按照模三的余数分类讨论
  1. 余数为一,可以算出所有格子的数字之和,再算出除了正中央格子以外所有格子的数字之和,很明显可以看出。
  2. 余数为二,同样可以很简单的算出除了正中央格子以外所有格子的数字之和。
  3. 余数为零,可以把正中央的格子算两次,再减去总数。

再把上面的结论推广到二维

利用这种方法算出每行和上下两行的地雷总数,相减就能得答案了。


Attention

这题的答案其实是唯一的,但是题面要求最大值,是一种误导。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
#include<utility>
#include<queue>
using namespace std;
 
#define MAX_RC 50
int R,C;
int A[MAX_RC][MAX_RC];
 
//计算长度为n的一维版问题的总和
int total(int *a,int n)
{
    int res=0;
    //按模3的余数讨论
    if(n%3==1||n%3==2){
        for(int i=0;i<n;i+=3){
            res+=a[i];
        }
    }
    else{
        for(int i=1;i<n;i+=3){
            res+=a[i];
        }
    }
    return res;
}
 
//计算长度为n的一维版问题正中央的数字
int center(int *a,int n)
{
    int res;
    //按模3的余数讨论
    if(n%3==1){
        res=total(a,n);
        for(int i=1;i<n/2;i+=3){
            res-=a[i];
            res-=a[n-1-i];
        }
    }
    else if(n%3==2){
        res=total(a,n);
        for(int i=0;i<n/2;i+=3){
            res-=a[i];
            res-=a[n-1-i];
        }
    }
    else{
        res=0;
        for(int i=0;i<n/2;i+=3){
            res+=a[i];
            res+=a[n-1-i];
        }
        res-=total(a,n);
    }
    return res;
}
int main()
{
    freopen("C-large-practice.in","r",stdin);
    freopen("C-large-practice.out","w",stdout);
    int t,kase=0;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&R,&C);
        for(int i=0;i<R;i++){
            for(int j=0;j<C;j++){
                scanf("%d",&A[i][j]);
            }
        }
        int row[MAX_RC];
        for(int i=0;i<R;i++){
            row[i]=total(A[i],C);
        }
        int ans=center(row,R);
        printf("Case #%d: %d\n",++kase,ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值