题目描述
食品店里有n个摄像头,这种摄像头很笨拙,只能拍摄到固定位置。现有一群胆大妄为的松鼠想要抢劫食品店,为了不让摄像头拍下他们犯罪的证据,他们抢劫前的第一件事就是砸毁这些摄像头。
为了便于砸毁摄像头,松鼠歹徒们把所有摄像头和摄像头能监视到的地方统一编号,一个摄像头能被砸毁的条件是该摄像头所在位置不被其他摄像头监视。
现在你的任务是帮松鼠们计算是否可以砸掉所有摄像头,如不能则输出还没砸掉的摄像头的数量。
输入输出格式
输入格式:
第1行,一个整数n,表示摄像头的个数。
第2到n+1行是摄像头的信息,包括:摄像头的位置x,以及这个摄像头可以监视到的位置数m,之后m个数y是此摄像头可以监视到的位置。(砸了这些摄像头之后自然这些位置就监视不到了)
输出格式:
若可以砸掉所有摄像头则输出“YES”,否则输出还没砸掉的摄像头的数量。
输入输出样例
输入样例#1:
5 1 1 2 2 1 1 3 1 7 4 1 1 5 0
输出样例#1:
2
解题思路
这题可以说是2015noipd1t2信息传递的简化版,这题只用按拓扑排序依次把入度为0的点删掉,再统计没被删的有多少就行了,信息传递那题还要统计剩下的点中的最小环。还有一个不同是这题要把摄像机编号和位置用map离散化一下。大概思路就是这样,详细步骤在代码注释里
源代码
#include<cstdio> #include<vector> #include<map> using namespace std; int n;//摄像头总数 map<int,int> ma;//离散化位置到编号(ca中下标) struct camera{ int num,in;//儿子数(似乎后面没用到)、入度 vector<int> son;//儿子们的位置 }temp;//temp是方便输入的临时变量 vector<camera> ca;//吐槽题目不给数据范围 void del(int x)//x是摄像机编号,即在ca中的下标 { int size=ca[x].son.size(); for(int i=0;i<size;i++)//便遍历第x号摄像机的儿子的位置 { if(ma.count(ca[x].son[i])) //如果这个位置确实有摄像机(有两个数据点的摄像机拍摄到了没有其他摄像机的空位置,导致我开始只有80分) { ca[ma[ca[x].son[i]]].in--;//儿子摄像机的入度减1 if(ca[ma[ca[x].son[i]]].in<=0)//减到0了 { del(ma[ca[x].son[i]]);//就把这个儿子也删了吧 } } } } int main() { scanf("%d",&n); for(int i=0,lo,so;i<n;i++)//lo位置、so儿子数 { scanf("%d%d",&lo,&so); ma[lo]=i;//离散化! temp.num=so; temp.in=0;//入度清零 for(int j=0;j<so;j++) { scanf("%d",&lo); temp.son.push_back(lo);//输入各个儿子的位置 } ca.push_back(temp); } for(int i=0;i<n;i++)//遍历ca[]每一台摄像机,增加它们儿子的入度 { for(int j=0;j<ca[i].son.size();j++)//遍历ca[i]能拍到的的每个位置 { if(ma.count(ca[i].son[j]))//如果这个位置有也摄像机 ca[ma[ca[i].son[j]]].in++;//增加入度 } } for(int i=0;i<n;i++) { if(ca[i].in<=0)//入度为零就删了 { del(i); } } int ans=0; for(int i=0;i<n;i++)//统计有多少摄像机还没被砸 { if(ca[i].in>0) ans++; } if(ans==0) printf("YES");//全砸了,抢劫成功 else printf("%d",ans);//砸不完,输出剩下的摄像机数量 return 0; }