CSP202206-2 寻宝!大冒险!

题目描述

在这里插入图片描述

输入输出样例

样例1

  • 输入
    5 100 2
    0 0
    1 1
    2 2
    3 3
    4 4
    0 0 1
    0 1 0
    1 0 0
    
  • 输出
    3
    
  • 解释
    在这里插入图片描述

样例2

  • 输入
    5 4 2
    0 0
    1 1
    2 2
    3 3
    4 4
    0 0 0
    0 1 0
    1 0 0
    
  • 输出
    0
    
  • 解释
    在这里插入图片描述

数据范围

在这里插入图片描述

题意描述 & 思路

  1. 有一张绿化图(蓝色)和藏宝图(橙色),其中绿化图很大(二维数组在限定的空间内无法存储),而藏宝图是绿化图中的一部分
    在这里插入图片描述
    对于绿化图和藏宝图,左下角的坐标为(0, 0),右上角的坐标是(L, L) (S, S),其实就是笛卡尔坐标系

  2. 题目保证藏宝图的左下角必定是树,因此可以从绿化图中的每一个树进行模拟,若该点(x, y)作为左下角,直到右上角(x+S, y+S)与藏宝图完全一致,说明该点符合题意,方案数+1

  3. 还需要注意,模拟时要保证面积与藏宝图一致,不能越界
    即:藏宝图是绿化图的一部分,符合题意的点,必须完全包含藏宝图
    图中只有红色部分相等是不满足题意的在这里插入图片描述

  4. 藏宝图的输入比较特殊,是从左上角开始输入,直到右下角
    在这里插入图片描述
    因此,若用 g 来表示藏宝图,保存时,从g[S][0]开始,一直到 g[S][S],这是第一行,第二行从g[S-1][0]g[S-1][S],用两个 for 循环即可

    	for(int i=S; i>=0; --i)
    		for(int j=0; j<=S; ++j)
    			cin >> g[i][j];
    
  5. 模拟时,首先取得绿化图中树的坐标,在该坐标的基础上进行运算
    check(a, b) 函数表示(a, b) 在绿化图中是否是 “树”

    bool f = true;
    int a = tree.x, b = tree.y;
    for(int i=0; i<=k; ++i)
    {
    	for(int j=0; j<=k; ++j)
    	{
    	    // (a, b) 是绿化图的左下角
    	    // (a + i, b + j) 表示绿化图中坐标相对于藏宝图的位置
    	    // 若 g[i][j] (藏宝图中是 1)并且绿化图中不是 1,那么不满足条件,退出
    		if(g[i][j] && !check(a + i, b + j))
    		{
    			f = false;
    			break;
    		}
    		// 若 !g[i][j] (藏宝图中是 0),并且绿化图中是 1,那么不满足条件,退出
    		if(!g[i][j] && check(a + i, b + j))
    		{
    			f = false;
    			break;
    		}
    	}
    	if(!f) break;
    }
    
  6. check 函数的实现,可以使用 set,保存输入数据中的 x, y

    typedef pair<int, int> PII;
    // t 中存储绿化图中所有的树
    set <PII> t;
    
    for(int i=0; i<n; ++i)
    {
    	int a, b;
    	cin >> a >> b;
    	t.insert({a, b});
    }
    

代码

  • 运行结果
    在这里插入图片描述
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

#define x first
#define y second

typedef pair<int, int> PII;
const int N = 1010, M = 55;
// n : 树的个数
// m : 绿化图的大小
// k : 藏宝图的大小
// res : 符合题意的方案数 
int n, m, k, res;
// 藏宝图 
int g[N][N];
// 绿化图中树的坐标 
set <PII> t;

int main()
{
	cin >> n >> m >> k;
	for(int i=0; i<n; ++i)
	{
		int a, b;
		cin >> a >> b;
		t.insert({a, b});
	}
	
	for(int i=k; i>=0; --i)
		for(int j=0; j<=k; ++j)
			cin >> g[i][j];
	

	for(auto& tree : t)
	{
		bool f = true;
		int a = tree.x, b = tree.y;
		if(a + k > m || b + k > m) continue;
		for(int i=0; i<=k; ++i)
		{
			for(int j=0; j<=k; ++j)
			{
				if(g[i][j] && !t.count({a + i, b + j}))
				{
					f = false;
					break;
				}
				
				if(!g[i][j] && t.count({a + i, b + j}))
				{
					f = false;
					break;
				}
			}
			if(!f) break;
		}
		if(f) ++res;
	}
	cout << res << endl;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值