ZOJ 3811 —— Untrusted Patrol(2014牡丹江网络赛C题)

题目:Untrusted Patrol

题意:给定一个无向图,其中K个点有监控,每个监控在第一次访问该点的时候做记录,现在给出其中L个监控点的访问顺序,问是否存在路线使得满足上述顺序同时访问所有点。可以重复访问同一个点,但是有监控的只会在第一次访问做记录。

昨天比赛的时候挂了几发才过,代码也写得不成样子了。

今天重新想了下,发现其实只要写搜索就行,BFS或DFS都行。

昨天用的是BFS+并查集,并查集主要是判断图是否联通。

首先因为有K个监控,如果遍历完所有点肯定有L个记录,如果 L小于K就直接输出"No"。

接下来,先将读到的L个点标记为不可扩展ban[i]=true。

这里不妨设是从第一个记录到的点出发,先标记它为vis[i]=true

接下来按顺序访问L个记录,如果当前记录vis[x]=false,说明不能访问到它,return false

否则对它进行bfs,bfs到的点全部标记为vis[]=true,如果这个点还是ban[]=true的状态,就不把它加入队列。同时用一个extend[]表示是否扩展过,扩展过的就不要扩展了。

最后如果全部L个点访问完了,再扫一遍vis,看看是否还有未访问到的,这样就可以不用再写个并查集了。

PS:据说也有只用并查集的做法,待学习。

#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int N = 100010;
#define pb push_back
vector<int> V[N];
bool vis[N], extend[N], ban[N];
int T, m, n, K, L, l[N];
void bfs(int x){
    queue<int> Q;
    Q.push(x);
    while(!Q.empty()){
        x = Q.front(); Q.pop();
        if(extend[x])   continue;
        extend[x] = 1;
        for(int i=0; i<V[x].size(); i++){
            int j = V[x][i];
            if(vis[j]) continue;
            vis[j] = 1;
            if(!ban[j]) Q.push(j);
        }
    }
}
bool solve(){
    vis[l[0]] = 1;
    for(int i=0; i<L; i++){
        if(!vis[l[i]])   return 0;
        ban[l[i]] = 0;
        bfs(l[i]);
    }
    for(int i=1; i<=n; i++) if(!vis[i]) return 0;
    return 1;
}
int main(){
    scanf("%d", &T);
    while(T--){
        scanf("%d %d %d", &n, &m, &K);
        for(int i=1; i<=n; i++){
            V[i].clear();
            vis[i] = 0;
            ban[i] = 0;
            extend[i] = 0;
        }
        int a,b;
        for(int i=1; i<=K; i++) scanf("%d", &a);
        while(m--){
            scanf("%d %d", &a, &b);
            V[a].pb(b);
            V[b].pb(a);
        }
        scanf("%d", &L);
        for(int i=0; i<L; i++){
            scanf("%d", l+i);
            if(i)   ban[l[i]] = 1;
        }
        if(L<K) puts("No");
        else    puts(solve()?"Yes":"No");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值