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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/zrts/p/bzoj1574.html