ZOJ 3811 Untrusted Patrol 并查集 染色 BFS

题意:有N个城市,M条路。有K个传感器,分布在给定的K个城市中。传感器只会在第一次到达该城市时触发。现在给出传感器触发的先后顺序,问是否有方案遍历完所有的城市。

思路:第一点很容易想到的是:如果触发的传感器的数量少于传感器的总数量,那么一定没有遍历完所有城市。

          第二点:对于没有放传感器和传感器已经触发的城市,还有所有的路,我们的访问次数的无限制的。所以,我们这些城市的访问顺序是没有先后的,可以按照任意的顺序访问任意多次。现在问题的关键就是:能不能按照触发顺序访问完放置传感器的城市。我们可以有以下的思路:对于每个放置传感器的城市,我们可以通过搜索的得到从他出发,不触发任何传感器且能到达的城市。同时,这些城市中如果有一个和前面已经处理的城市的集合相连的路,那就可以得到一条路,按照传感器的触发顺序,到达前一个城市。之后将集合加入到已经处理的城市的集合,即,可以无限次访问的集合。如果找不到,那就说明无法到达前一个城市。

         第三点:整个图必须是连通的,要不然总会有一个点无法访问。

代码如下:

#include <bits/stdc++.h>

using namespace std;

const int MAX = 1000100;
int N,M,K,L;
int tot;
int head[MAX];
int nxt[MAX];
int to[MAX];
int used[MAX];
bool vis[MAX];
int order[MAX];
int que[MAX], front, tail;
int temp[MAX],ttop;
bool cn;

template<class T>
inline bool read(T &n){
    T x = 0, tmp = 1; char c = getchar();
    while ((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if (c == EOF) return false;
    if (c == '-') c = getchar(), tmp = -1;
    while (c >= '0' && c <= '9') x *= 10, x += (c - '0'), c = getchar();
    n = x*tmp;
    return true;
}

template <class T>
inline void write(T n) {
    if (n < 0) {
        putchar('-');
        n = -n;
    }
    int len = 0, data[20];
    while (n) {
        data[len++] = n % 10;
        n /= 10;
    }
    if (!len) data[len++] = 0;
    while (len--) putchar(data[len] + 48);
}
void init(){
    memset(head,-1,sizeof(int) * (N + 1));
    memset(used,0,sizeof(int)*(N+1));
    tot = 0;
}

void addedge(int u, int v){
    to[tot] = v;
    nxt[tot] = head[u]; head[u] = tot++;
    to[tot] = u;
    nxt[tot] = head[v]; head[v] = tot++;
}

bool bfs(int s){
    bool sig=false;
    ttop=0;
    front = tail = 0;
    que[tail++] = s;
    used[s] = 2;
    ttop++;
    temp[ttop]=s;
    while(front < tail){
        int u = que[front++];
        //printf("%d\n",u);
        for(int i = head[u]; i != -1; i = nxt[i]){
            int v = to[i];
            if (used[v]==1) sig=true;
            if(used[v] || vis[v]) continue;
            used[v]=2;
            ttop++;
            temp[ttop]=v;
            que[tail++] = v;
        }
    }
    for(int j=1;j<=ttop;j++)
    {
        used[temp[j]]=1;
    }
    return sig;
}

int main(void)
{
    //freopen("input.txt","r",stdin);
    int T;
    int tmp;
    int u,v;
    read(T);
    while(T--){
        read(N),read(M),read(K);
        init();
        memset(vis,0,sizeof(bool) * (N + 1));
        for(int i = 0 ; i < K; ++i)
            read(tmp);
        for(int i = 0; i < M; ++i){
            read(u),read(v);
            addedge(u,v);
        }
        read(L);
        for(int i = 0 ; i < L; ++i){
            read(order[i]);
            vis[order[i]] = true;
        }

        if(L < K ) puts("No");
        else{
            vis[order[0]] = false;
            bfs(order[0]);
            bool sig=true;
            for(int i = 1; i < K; ++i){
                vis[order[i]] = false;
                if (!bfs(order[i]))
                {
                    sig=false;
                    break;
                }
            }
            for (int i=1;i<=N;i++)
            {
                if (!used[i])
                {
                    sig=false;
                    break;
                }
            }
            if(sig) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值