题型:图论
题意:
无向图有N点M条边,有K个点是摄像头,摄像头只会记录第一次到达的时间。现给出一个长度为L的摄像头序列,问是否能够按照这个序列走过图中所有的点。
分析:
如果L<K,那么显然是不能到达所有的点的,因为序列中有的摄像头没走到。
也可以想到,如果这个图是不连通的,那么也是不能到达所有的点的。这个可以用并查集轻松解决。
若要根据序列去走,假设序列为“321......”,那么从3点到2点,就不能经过序列中“2”之后的所有点,例如“3->1->2”,所以只能直接到或者通过没有摄像头的无关点。可以先将所有有联系的无关点加入到并查集中,然后遍历序列,例如上述序列,先将3点标记为无关点,然后把所有与3点连接的无关点加入并查集;然后将2点标记为无关点,然后把所有与2点连接的无关点加入到并查集中;然后查询3点与2点是否在一个集合中。,以此类推下去。这样就能保证3点到达2点不会经过其他的摄像头。
代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#define mt(a,b) memset(a,b,sizeof(a))
#define LL long long
using namespace std;
const int M = 200020;
struct G {
struct E {
int u,v,next;
} e[M*2];
int head[M],le;
void init() {
le = 0;
mt(head,-1);
}
void add(int u,int v) {
e[le].u = u;
e[le].v = v;
e[le].next = head[u];
head[u] = le++;
}
} g;
class UnionFindSet { //并查集
int par[M];
public:
void init() {
mt(par,-1);
}
int getroot(int x) {
int i=x,j=x,temp;
while(par[i]>=0) i=par[i];
while(j!=i) {
temp=par[j];
par[j]=i;
j=temp;
}
return i;
}
bool unite(int x,int y) {
int p=getroot(x);
int q=getroot(y);
if(p==q)return false;
if(par[p]>par[q]) {
par[q]+=par[p];
par[p]=q;
} else {
par[p]+=par[q];
par[q]=p;
}
return true;
}
} ts;
bool mark[100020];
int viwer[100020];
int main() {
int _;
scanf("%d",&_);
int n,m,k,l;
while(_--) {
scanf("%d%d%d",&n,&m,&k);
mt(mark,false);
int tmp;
for(int i=0; i<k; i++) {
scanf("%d",&tmp);
mark[tmp] = true;
}
g.init();
for(int i=0; i<m; i++) {
int u,v;
scanf("%d%d",&u,&v);
g.add(u,v);
g.add(v,u);
}
scanf("%d",&l);
for(int i=0;i<l;i++){
scanf("%d",&viwer[i]);
}
if(k!=l) {
puts("No");
continue;
}
ts.init();
//connect all unrelated point
for(int x=1; x<=n; x++) {
if(!mark[x]) {
for(int i=g.head[x]; ~i; i=g.e[i].next) {
int u = g.e[i].u;
int v = g.e[i].v;
ts.unite(u,v);
}
}
}
bool ans = true;
//connect viewer
for(int x=0; x<k; x++) {
int u = viwer[x];
mark[u] = false;
for(int i=g.head[u]; ~i; i=g.e[i].next) {
int v = g.e[i].v;
if(!mark[v]) ts.unite(u,v);
}
if(x>0){
if(ts.getroot(viwer[x-1]) != ts.getroot(u)){
ans = false;
break;
}
}
}
if(ans){
int num = 0;
for(int i=1;i<=n;i++){
if(ts.getroot(i)==i) num++;
}
if(num>1){
ans = false;
}
}
if(ans) puts("Yes");
else puts("No");
}
return 0;
}