BZOJ 1574: [Usaco2009 Jan]地震损坏Damage
Description
农夫John的农场遭受了一场地震.有一些牛棚遭到了损坏,但幸运地,所有牛棚间的路经都还能使用. FJ的农场有P(1 <= P <= 30,000)个牛棚,编号1..P. C(1 <= C <= 100,000)条双向路经联接这些牛棚,编号为1..C. 路经i连接牛棚a_i和b_i (1 <= a_i<= P;1 <= b_i <= P).路经可能连接a_i到它自己,两个牛棚之间可能有多条路经.农庄在编号为1的牛棚. N (1 <= N <= P)头在不同牛棚的牛通过手机短信report_j(2 <= report_j <= P)告诉FJ它们的牛棚(report_j)没有损坏,但是它们无法通过路经和没有损坏的牛棚回到到农场. 当FJ接到所有短信之后,找出最小的不可能回到农庄的牛棚数目.这个数目包括损坏的牛棚. 注意:前50次提交将提供在一些测试数据上的运行结果.
Input
* 第1行: 三个空格分开的数: P, C, 和 N
* 第2..C+1行: 每行两个空格分开的数: a_i 和 b_i * 第C+2..C+N+1行: 每行一个数: report_j
Output
* 第1行: 一个数,最少不能回到农庄的牛的数目(包括损坏的牛棚).
题解:
对于一个report_j,我们只能知道j和与j相连的点都回不到农场。
于是把这些点标记一下,bfs时不访问这些点,统计个数即可。
代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<queue> //by zrt //problem: using namespace std; int H[30005],X[210000],P[210000],tot; int p,c,n; inline void add(int x,int y){ P[++tot]=y;X[tot]=H[x];H[x]=tot; } bool mark[30005]; bool vis[30005]; queue<int> q; int main(){ #ifdef LOCAL freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif scanf("%d%d%d",&p,&c,&n); for(int i=0,x,y;i<c;i++){ scanf("%d%d",&x,&y); add(x,y);add(y,x); } for(int i=0,x;i<n;i++){ scanf("%d",&x); for(int j=H[x];j;j=X[j]){ mark[P[j]]=1; } } q.push(1); while(!q.empty()){ int x=q.front();q.pop(); vis[x]=1; for(int i=H[x];i;i=X[i]){ if(!mark[P[i]]&&!vis[P[i]]){ q.push(P[i]); } } } int ans=0; for(int i=2;i<=p;i++){ if(!vis[i]) ans++; } printf("%d\n",ans); return 0; }