ZOJ 3811 Untrusted Patrol 并查集(转自九野巨巨)
题目链接:点击打开链接
题意:
给定n个点m条边的无向图,k个触发器。
下面k个数表示触发器安装在哪几个点。
下面m行给出边
最后有l个信号,
给出信号发出的触发器的顺序。
每个触发器只会发出一次信号,且一个点只有一个触发器。
有一个人在遍历图。
每经过一个点,那个点的触发器就会发出信号,问是否存在一种走法使得这个人遍历了所有点且触发器发出的信号顺序和给出的一样。
思路:
先把无触发器的点放到图里。
然后根据触发器的信号顺序把点依次加入图中,加入时只添加(与无触发器点相连的边)
然后判断这个点能否与之前的图连通。bfs+并查集判断。
==其实并查集就够了,写的时候有脑洞,bfs就冒出来了
- #include<stdio.h>
- #include<string.h>
- #include<iostream>
- #include<algorithm>
- #include<vector>
- #include <queue>
- using namespace std;
- #define ll int
- typedef pair<int,int> pii;
- #define M 400010
- #define N 200010
- int f[N];
- int find(int x){return x==f[x]?x:f[x] = find(f[x]);}
- void Union(int x,int y){
- int fx = find(x), fy = find(y);
- if(fx==fy)return ;
- if(fx>fy)swap(fx,fy);
- f[fx] = fy;
- }
- struct Edge{
- int from, to, nex;
- }edge[M<<1];
- int head[N], edgenum;
- void init(){memset(head, -1, sizeof head); edgenum = 0;}
- void add(int u, int v){
- Edge E = {u, v, head[u]};
- edge[edgenum] = E;
- head[u] = edgenum++;
- }
- int n, m, k, l;
- int is[N], vis[N];
- vector<int>G, E[N];
- void ADD(int x){
- for(int i = 0; i < E[x].size(); i++){
- if(is[E[x][i]] == 0)
- add(x, E[x][i]);
- }
- is[x] = 0;
- }
- void bfs(int x){
- queue<int>q; q.push(x);
- vis[x] = 1;
- while(!q.empty()){
- int u = q.front(); q.pop();
- for(int i = head[u]; ~i; i = edge[i].nex)
- {
- int v = edge[i].to;
- Union(v, x);
- if(vis[v])continue;
- vis[v] = 1;
- q.push(v);
- }
- }
- }
- bool solve(){
- scanf("%d %d %d",&n,&m, &k);
- init();
- int i, j, u, v;
- for(i = 1; i <= n; i++) {
- vis[i] = is[i] = 0;
- E[i].clear();
- }
- for(i = 1; i <= k; i++) { scanf("%d",&j); is[j] = 1; }
- while(m--){
- scanf("%d %d", &u, &v);
- E[u].push_back(v); E[v].push_back(u);
- }
- G.clear();
- scanf("%d", &l);
- for(i = 1; i <= l; i++) { scanf("%d", &j); G.push_back(j); }
- //若触发器没有全响,就不行
- if(k!=l)return false;
- //若没有触发器一定可以。
- if(k == 0) return true;
- for(i = 1; i <= n; i++)
- {
- if(is[i] == 0)
- {
- for(j = 0; j < E[i].size(); j++)
- if(is[E[i][j]]==0)
- add(i, E[i][j]);
- }
- }
- for(i = 1; i <= n; i++) f[i] = i;
- for(i = 0; i < G.size(); i++) {
- u = G[i];
- ADD(u);
- bfs(u);
- if(i-1>=0){
- find(G[i]); find(G[i-1]);
- if(f[G[i]] != f[G[i-1]])
- return false;
- }
- }
- for(i = 1; i <= n; i++) if(vis[i] == 0) return false;
- return true;
- }
- int main(){
- int T; scanf("%d",&T);
- while(T--)
- solve() ? puts("Yes"):puts("No");
- return 0;
- }
- /*
- 99
- 5 5 3
- 1 2 4
- 1 2
- 2 3
- 3 1
- 1 4
- 4 5
- 3
- 4 2 1
- 5 5 3
- 1 2 4
- 1 2
- 2 3
- 3 1
- 1 4
- 4 5
- 3
- 4 1 2
- 7 8 3
- 1 3 5
- 1 2
- 1 3
- 2 3
- 2 4
- 3 6
- 5 4
- 5 7
- 6 7
- 3
- 5 3 1
- 7 8 5
- 3 6 4 5 7
- 1 2
- 1 3
- 2 3
- 2 4
- 3 6
- 5 4
- 5 7
- 6 7
- 5
- 3 6 4 5 7
- 7 8 5
- 3 6 4 5 7
- 1 2
- 1 3
- 2 3
- 2 4
- 3 6
- 5 4
- 5 7
- 6 7
- 5
- 3 6 5 4 7
- 8 8 5
- 3 6 4 5 7
- 1 2
- 1 3
- 2 3
- 2 4
- 3 6
- 5 4
- 5 7
- 6 7
- 5
- 3 6 4 5 7
- ans:
- N
- Y
- Y
- Y
- N
- N
- */
自己赛后补题,代码如下:
#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;
}