ZOJ 3811 Untrusted Patrol 并查集

ZOJ 3811 Untrusted Patrol 并查集(转自九野巨巨)

分类: 图论 BFS 并查集   562人阅读  评论(1)  收藏  举报

题目链接:点击打开链接

题意:

给定n个点m条边的无向图,k个触发器。

下面k个数表示触发器安装在哪几个点。

下面m行给出边

最后有l个信号,

给出信号发出的触发器的顺序。

每个触发器只会发出一次信号,且一个点只有一个触发器。

有一个人在遍历图。

每经过一个点,那个点的触发器就会发出信号,问是否存在一种走法使得这个人遍历了所有点且触发器发出的信号顺序和给出的一样。

思路:

先把无触发器的点放到图里。

然后根据触发器的信号顺序把点依次加入图中,加入时只添加(与无触发器点相连的边)

然后判断这个点能否与之前的图连通。bfs+并查集判断。

==其实并查集就够了,写的时候有脑洞,bfs就冒出来了

[cpp]  view plain copy
  1. #include<stdio.h>  
  2. #include<string.h>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #include<vector>  
  6. #include <queue>  
  7. using namespace std;  
  8. #define ll int  
  9. typedef pair<int,int> pii;  
  10. #define M 400010  
  11. #define N 200010  
  12. int f[N];  
  13. int find(int x){return x==f[x]?x:f[x] = find(f[x]);}  
  14. void Union(int x,int y){  
  15.     int fx = find(x), fy = find(y);  
  16.     if(fx==fy)return ;  
  17.     if(fx>fy)swap(fx,fy);  
  18.     f[fx] = fy;  
  19. }  
  20. struct Edge{  
  21.     int from, to, nex;  
  22. }edge[M<<1];  
  23. int head[N], edgenum;  
  24. void init(){memset(head, -1, sizeof head); edgenum = 0;}  
  25. void add(int u, int v){  
  26.     Edge E = {u, v, head[u]};  
  27.     edge[edgenum] = E;  
  28.     head[u] = edgenum++;  
  29. }  
  30. int n, m, k, l;  
  31. int is[N], vis[N];  
  32. vector<int>G, E[N];  
  33. void ADD(int x){  
  34.     for(int i = 0; i < E[x].size(); i++){  
  35.         if(is[E[x][i]] == 0)  
  36.         add(x, E[x][i]);  
  37.     }  
  38.     is[x] = 0;  
  39. }  
  40. void bfs(int x){  
  41.     queue<int>q; q.push(x);  
  42.     vis[x] = 1;  
  43.     while(!q.empty()){  
  44.         int u = q.front(); q.pop();  
  45.         for(int i = head[u]; ~i; i = edge[i].nex)  
  46.         {  
  47.             int v = edge[i].to;  
  48.             Union(v, x);  
  49.             if(vis[v])continue;  
  50.             vis[v] = 1;  
  51.             q.push(v);  
  52.         }  
  53.     }  
  54. }  
  55. bool solve(){  
  56.     scanf("%d %d %d",&n,&m, &k);  
  57.     init();  
  58.     int i, j, u, v;  
  59.     for(i = 1; i <= n; i++) {  
  60.         vis[i] = is[i] = 0;  
  61.         E[i].clear();  
  62.     }  
  63.     for(i = 1; i <= k; i++) { scanf("%d",&j); is[j] = 1; }  
  64.     while(m--){  
  65.         scanf("%d %d", &u, &v);  
  66.         E[u].push_back(v); E[v].push_back(u);  
  67.     }  
  68.     G.clear();  
  69.     scanf("%d", &l);  
  70.     for(i = 1; i <= l; i++) { scanf("%d", &j); G.push_back(j); }  
  71.     //若触发器没有全响,就不行  
  72.     if(k!=l)return false;  
  73.     //若没有触发器一定可以。  
  74.     if(k == 0) return true;  
  75.     for(i = 1; i <= n; i++)  
  76.     {  
  77.         if(is[i] == 0)  
  78.         {  
  79.             for(j = 0; j < E[i].size(); j++)  
  80.                 if(is[E[i][j]]==0)  
  81.                     add(i, E[i][j]);  
  82.         }  
  83.     }  
  84.     for(i = 1; i <= n; i++) f[i] = i;  
  85.     for(i = 0; i < G.size(); i++) {  
  86.         u = G[i];  
  87.         ADD(u);  
  88.         bfs(u);  
  89.         if(i-1>=0){  
  90.             find(G[i]); find(G[i-1]);  
  91.             if(f[G[i]] != f[G[i-1]])  
  92.                 return false;  
  93.         }  
  94.     }  
  95.     for(i = 1; i <= n; i++) if(vis[i] == 0) return false;  
  96.     return true;  
  97. }  
  98. int main(){  
  99.     int T; scanf("%d",&T);  
  100.     while(T--)  
  101.         solve() ? puts("Yes"):puts("No");  
  102.     return 0;  
  103. }  
  104. /* 
  105. 99 
  106. 5 5 3 
  107. 1 2 4 
  108. 1 2 
  109. 2 3 
  110. 3 1 
  111. 1 4 
  112. 4 5 
  113. 3 
  114. 4 2 1 
  115. 5 5 3 
  116. 1 2 4 
  117. 1 2 
  118. 2 3 
  119. 3 1 
  120. 1 4 
  121. 4 5 
  122. 3 
  123. 4 1 2 
  124.  
  125. 7 8 3 
  126. 1 3 5 
  127. 1 2 
  128. 1 3 
  129. 2 3 
  130. 2 4 
  131. 3 6 
  132. 5 4 
  133. 5 7 
  134. 6 7 
  135. 3 
  136. 5 3 1 
  137.  
  138. 7 8 5 
  139. 3 6 4 5 7 
  140. 1 2 
  141. 1 3 
  142. 2 3 
  143. 2 4 
  144. 3 6 
  145. 5 4 
  146. 5 7 
  147. 6 7 
  148. 5 
  149. 3 6 4 5 7 
  150.  
  151. 7 8 5 
  152. 3 6 4 5 7 
  153. 1 2 
  154. 1 3 
  155. 2 3 
  156. 2 4 
  157. 3 6 
  158. 5 4 
  159. 5 7 
  160. 6 7 
  161. 5 
  162. 3 6 5 4 7 
  163.  
  164. 8 8 5 
  165. 3 6 4 5 7 
  166. 1 2 
  167. 1 3 
  168. 2 3 
  169. 2 4 
  170. 3 6 
  171. 5 4 
  172. 5 7 
  173. 6 7 
  174. 5 
  175. 3 6 4 5 7 
  176.  
  177. ans: 
  178. N 
  179. Y 
  180. Y 
  181. Y 
  182. N 
  183. N 
  184.  
  185. */  

自己赛后补题,代码如下:

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstdlib>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define CLR(a,x) memset(a,x,sizeof(a))
const int maxn=1e5+5;
int m,n,k,L;
vector<int>G[maxn];
int p[maxn],is_sen[maxn];
int findx(int x){return p[x]==x?x:p[x]=findx(p[x]);}
void Union(int x,int y)
{
    p[findx(x)]=findx(y);
}
void Init(int n)
{
     for(int i=1;i<=n;i++){
        G[i].clear();
        is_sen[i]=0;
        p[i]=i;
     }
}
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	int T;
	cin>>T;
	while(T--)
    {
        cin>>n>>m>>k;
        int x;
        Init(n);

        for(int i=1;i<=k;i++){
            cin>>x;
            is_sen[x]=1;
        }

        int u,v;
        while(m--){
            cin>>u>>v;
            G[v].pb(u);
            G[u].pb(v);
        }

        cin>>L;
        bool ok=true;
        if(L<k)ok=false;
        if(ok)for(int i=1;i<=n;i++)if(!is_sen[i]){///加入所有不含传感器的边,更新联通分量
            for(vector<int>::iterator it=G[i].begin();it!=G[i].end();++it){
                v=*it;
                if(!is_sen[v]){
                    Union(v,i);
                }
        }
        }
        int bfor;
        for(int i=1;i<=L;i++){///按传感器记录顺序更新联通分量
            cin>>u;
            if(ok)for(vector<int>::iterator it=G[u].begin();it!=G[u].end();++it){
                v=*it;
                if(!is_sen[v]){
                    Union(v,u);
                }
            }
            if(i==1){
                bfor=findx(u);
            }
            else if(findx(u)!=findx(bfor)){///加边之后不联通,不能从上一个传感器到下一个
                ok=false;
            }
            is_sen[u]=0;///已经访问过后下次可以添加这个点了(因为一个传感器只能记录最初的那次)
        }
        bfor=findx(1);
        for(int i=1;ok&&i<=n;i++)if(findx(i)!=bfor)///图不连通,不能访问所有的点
        {
            ok=false;
        }
        if(ok)puts("Yes");
        else puts("No");
    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值