洛谷 P2712 摄像头

文章介绍了如何通过编程解决松鼠砸毁摄像头以规避监控的问题,涉及结构体、map数据结构及遍历策略。
摘要由CSDN通过智能技术生成

 题目描述

食品店里有 �n 个摄像头,这种摄像头很笨拙,只能拍摄到固定位置。现有一群胆大妄为的松鼠想要抢劫食品店,为了不让摄像头拍下他们犯罪的证据,他们抢劫前的第一件事就是砸毁这些摄像头。

为了便于砸毁摄像头,松鼠歹徒们把所有摄像头和摄像头能监视到的地方统一编号,一个摄像头能被砸毁的条件是该摄像头所在位置不被其他摄像头监视。

现在你的任务是帮松鼠们计算是否可以砸掉所有摄像头,如不能则输出还没砸掉的摄像头的数量。

输入格式

第 11 行,一个整数 �n,表示摄像头的个数。

第 22 到 �+1n+1 行是摄像头的信息,包括:摄像头的位置 �x,以及这个摄像头可以监视到的位置数 �m,之后 �m 个数 �y 是此摄像头可以监视到的位置。(砸了这些摄像头之后自然这些位置就监视不到了)

输出格式

若可以砸掉所有摄像头则输出“ YESYES ”,否则输出还没砸掉的摄像头的数量。(不带引号)

输入输出样例

输入 #1复制

5
1 1 2
2 1 1
3 1 7
4 1 1
5 0

输出 #1复制

2

说明/提示

1≤�≤1001≤n≤100。

0≤�≤1000≤m≤100。

0≤�,�≤5000≤x,y≤500。

分析:

        对于该问题呢,主要难点有两个,第一个问题是理清楚结构体和map的关系;第二个问题是什么时候停止遍历。

        对于第一个问题,我们要先构建摄像头结构体vi,里边有sit是摄像头所在的位置,m是可以监视几个点,vrr指的是检视点是哪几个,sign是判断这个摄像头有没有被砸坏。那么容易让大家混乱的地方在哪呢,在于map和vrr还有sit的叠加。我们举个例子 map[arr[i].vrr[j]]=1 指的什么?指的是在map地图上,被摄像头i监视的第j个点有一个摄像头监视着他。在举个例子 map[arr[i].sit]==0 指的什么?指的是在地图map上,摄像头i所在的那个点没有摄像头监视着他;(这个地方可能比较绕,大家仔细想一下)

        对于第二个问题,什么时候停止遍历呢,当我们再一次遍历的时候,发现没有一个摄像头可以被砸坏,这样的话我们就没必要再去进行遍历了,那么停止遍历就行了。那么怎么实现呢?这里我用了do while型,再借助num实现。(do while和while差不多,区别就是do while是先运行do里边的内容,然后判断一下while,如果满足再进行遍历;while呢是先进行判断再决定要不要遍历)

        OK,上代码

代码:

#include<iostream>
using namespace std;
typedef struct v
{
	int sit;//位置
	int m;//有几个监视点
	int vrr[105];//分别是哪几个
	bool sign;//是否被砸
}vi;
vi arr[105];//摄像头
int map[505];
int n, ans, num, res;//res记录被砸毁的数量
int main()
{
	cin >> n;
	ans = n;//记录摄像头总数
	for (int i = 1; i <= n; i++)
	{
		cin >> arr[i].sit >> arr[i].m;
		for (int j = 1; j <= arr[i].m; j++)
		{
			cin >> arr[i].vrr[j];
			map[arr[i].vrr[j]]++;//该点被监视就加一,这个点的数值代表被几个摄像头监视
		}
	}
	do
	{
		num = 0;//用来检测这一遍循环有没有摄像头被砸坏
		for (int i = 1; i <= n; i++)//遍历摄像头
		{
			if (arr[i].sign)
				continue;
			if (map[arr[i].sit]==0)//该点不被监视
			{
				arr[i].sign = true;//被砸毁
				num = 1;//标记一下,这次循环还有摄像头被砸
				res++;//被砸数加一
				for (int j = 1; j <= arr[i].m; j++)//遍历可监视的点
					map[arr[i].vrr[j]]--;//被砸毁了那么这个点就--
			}
		}
	} while (num != 0);//如果没有摄像头被砸坏,那么就没必要在遍历了
	if (res != n)//如果没有全砸坏
		cout << n - res;
	else
		cout << "YES";
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值