题目描述
食品店里有 �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;
}