首页 > 其他分享 >P2484 [SDOI2011]打地鼠 题解

P2484 [SDOI2011]打地鼠 题解

时间:2022-11-04 21:44:47浏览次数:80  
标签:击打 int 题解 long SDOI2011 地鼠 P2484 锤子

P2484 [SDOI2011]打地鼠 题解

目录

题目

P2484 [SDOI2011]打地鼠 题解

分析

锤子每次只能将每个洞里打掉一只地鼠,所以对于每次击打,都会打掉 \(r\times c\) 只地鼠。而每次击打的范围内的每个洞里必须都要有地鼠,所以地鼠的总数必须被 \(r\times c\) 整除。

因为每只地鼠都需要被干掉,所以如果当前方案成立,总可以通过不断在地图左上角寻找有地鼠的洞,再以这个洞为锤子击打的范围的左上角进行击打来打完所有地鼠。

而如果在打地鼠的时候发现击打范围内有已经没有地鼠的洞或者会打到地图外面的话,当前方案就不成立。

思路

由于地图只是个 \(100\times 100\) 的矩形,所以我们完全可以枚举 \(r\) 和 \(c\),只要锤子覆盖的区域大小即 \(r\times c\) 能整除地图中的地鼠总数就进行尝试。

根据上文的分析,我们只需要在整个地图左上角找到一个还剩的有地鼠的洞,设这个洞的坐标为 \((x,y)\),然后进行以下操作:

  1. 判断 \((x+r-1,y+c-1)\) 是否在地图外面。在的话说明这个锤子不满足题意,结束,否则进行下一步。
  2. 判断\((x,y)\) 到 \((x+r-1,y+c-1)\) 范围内有没有空地鼠洞。如果有的话,说明这个锤子不满足题意,结束,否则进行下一步。
  3. 将 \((x,y)\) 到 \((x+r-1,y+c-1)\) 范围内的地鼠数量减一。
  4. 将这个锤子的击打总次数加一。
  5. 回到第 \(1\) 步操作直到所有地鼠洞为空。

因为 \((x+y)\) 的地鼠在锤子大小满足题意的情况下再怎么样都会被打完,所以我们也可以直接将 \((x,y)\) 到 \((x+r-1,y+c-1)\) 范围内的地鼠数量减 \((x,y)\) 里的地鼠数量(相当于连续打 \((x,y)\) 里的地鼠数量次),判断减之后有没有为负的洞,有说明锤子不满足题意,没有的话将锤子总击打次数加上 \((x,y)\) 里的地鼠数量,然后继续尝试。这算是个小优化。

最后就输出所有可行的锤子中击打次数最小的值就好了。更详细的解释请参阅代码里的注释。

代码

#pragma GCC optimize(2)
#include <cstdio>
using namespace std;
int n, m, tot = 0;
long long ans = 1145141919810;
int maze[105][105];
int tmaze[105][105]; //因为要尝试多次且每次尝试都会修改地鼠洞内地鼠的数量,
                     //我们需要在每次尝试前复制原始的地图
long long Min(long long a, long long b)
{
    return a > b ? b : a;
}
inline bool findfirst(int &x, int &y) //从地图左上角找到第一个有地鼠的地鼠洞,返回是否找到
{
    for (register int i = 1; i <= n; i++)
    {
        for (register int j = 1; j <= m; j++)
        {
            if (tmaze[i][j])
            {
                x = i, y = j; //找到就将这个洞的坐标传回去
                return 1;
            }
        }
    }
    return 0;
}
inline void dfs(int r, int c, int cnt) //参数表示锤子大小和花费
{
    int x, y;             //用x,y表示目前在左上角找到的地鼠洞为(x,y)
    if (!findfirst(x, y)) //如果没找到有地鼠的洞说明找完了,更新答案并结束
    {
        ans = Min(ans, 1ll * cnt);
        return;
    }
    if (x + r - 1 > n || y + c - 1 > m || cnt >= ans) //操作1,如果要打左上角的地鼠
                                                      //洞锤子会超过地图,说明这组
                                                      //方案不成立
        return;
    int red = tmaze[x][y]; //操作3,将(x,y)到(x+r-1,y+c-1)内的地鼠数量都减去(x,y)内的地鼠数
    for (register int i = x; i <= x + r - 1; i++)
    {
        for (register int j = y; j <= y + c - 1; j++)
        {
            tmaze[i][j] -= red;
            if (tmaze[i][j] < 0) //操作2,如果这个洞里的地鼠数量为负说明这组方案不成立
                return;
        }
    }
    dfs(r, c, cnt + red); //操作4、5,加上操作次数,继续打剩下的地鼠
    return;
}
void cpymaze()
{
    for (register int i = 1; i <= n; i++)
        for (register int j = 1; j <= m; j++)
            tmaze[i][j] = maze[i][j]; //复制原始的地图
}
signed main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            scanf("%d", &maze[i][j]);
            tot += maze[i][j]; //记录地鼠总数
        }
    }
    for (int r = 1; r <= n; r++)
    {
        for (int c = 1; c <= m; c++)
        {
            if (tot % (r * c) == 0) //分析中所说的,只有锤子的覆盖大小能整除地鼠总数才行
            {
                cpymaze();
                dfs(r, c, 0);
            }
        }
    }
    printf("%lld\n", ans);
}

标签:击打,int,题解,long,SDOI2011,地鼠,P2484,锤子
From: https://www.cnblogs.com/if-OF/p/P2484.html

相关文章

  • P7365 [CTSC2002]颁奖典礼 题解
    一道神奇的有关网格的DP(一些大佬称其为暴力DP)。这里将“I”字母分为的三个部分称为第一,二,三部分。做法:设fi,j,k,l(l∈[1,3])表示第i行,当前在第l部分,区间[j,k]的......
  • 矩阵树定理学习笔记 & 洛谷 P4111 [HEOI2015]小 Z 的房间 题解
    矩阵树定理拉普拉斯矩阵无边权设无向图\(G\)有\(n\)个结点,则拉普拉斯矩阵\(L\)是一个\(n\timesn\)的矩阵,满足:\(L_{i,i}(i\inG)\)的值为结点\(i\)的度数......
  • 【题解】Luogu P8743 【[蓝桥杯 2021 省 A] 异或数列】
    最近刚好在刷博弈论,看到这道题没有题解,所以刚好来水一发题目链接[蓝桥杯2021省A]异或数列题目描述Alice和Bob正在玩一个异或数列的游戏。初始时,Alice和Bob......
  • Atcoder Beginner Contest ABC 275 Ex (H) Monster 题解
    先明确\(a_i\)是一个怪物的血量,\(b_i\)是攻击的代价。发现如果我们想攻击一个怪物,不如找出一个极大的包含它的区间,满足这个区间内所有怪物的攻击代价都不大于它本身的代价,......
  • 【题解】洛谷 P1134 [USACO3.2]阶乘问题
     1#include<iostream>2usingnamespacestd;34intmain(){5intn;6cin>>n;7intc=1,a=0,b=0;8for(inti=1;i......
  • LG4026 [SHOI2008]循环的债务 题解
    LG4026[SHOI2008]循环的债务给出三个整数\(x_1,x_2,x_3\)。\(x_1\)代表A欠B的钱数,\(x_2\)表示B欠C的钱数,\(x_3\)表示C欠A的钱数。接下来\(3\)行,每......
  • WiredTiger引擎编译 及 LT_PREREQ(2.2.6)问题解决
    近期需要为异构引擎做准备,wiredtiger以其优异的性能(B-tree和LSM-tree都支持)和稳定性(Mongodb的默认存储引擎)被我们备选为异构引擎里的一个子引擎,后续将深入wiredtiger......
  • CF 1749 题解
    比赛链接:https://codeforces.com/contest/1749题解:AB水题//bySkyRainWind#include<cstdio>#include<vector>#include<cstring>#include<iostream>#include......
  • P4774 倚天屠龙传 题解
    其实这道题的主体并不难,主要是细节很多我们可以把题目分成界限分明的两部分,第一部分,屠每条龙所用的剑只和当前拥有的剑有关。于是可以单独开一个数据结构按题目维护。另......
  • 2022 CSP-S题解
    T1:假期计划给定\(n\)个点\(m\)条边的无向图,每个点有一个点权。在图中选\(4\)个不同的点,从\(1\)号点出发完成\(5\)段行程:\(1\toA\toB\toC\toD\to1\),每......