题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5343
大致题意:给定一张图,再给出一个顶点编号的序列,问是否在这张图上是否能按这个顺序依次访问这些顶点(题目描述的很复杂抽象出来就是这样的一个问题)。
大致思路:用并查集算法,先按题目条件建图,我们假设有放置传感器的顶点为k类顶点,没有放置传感器的顶点为o类顶点,我们将k类顶点按所给顺序存好,我们就能将原问题转化成另外一个问题,就是相邻的两个k点,是否能通过o点和之前出现过的k类相连接。
所以,我们将两两相连的o类顶点先合到一个集合中,再将第一个k点所连的所有顶点合并到一起,接下来处理剩下的每个k类顶点,首先将此顶点所连的所有非k类顶点加入到集合中,再判断这个k类顶点和它前一个k类顶点是否是联通的,如果不联通可以直接输出No,再将此k类顶点的相连的所有k类顶点合并在一起,再将此k类顶点和前一个k类顶点合并在一起,这样的循环操作~~~。
注意要判一下图是否是联通的,和L是否小于K。
图不联通和L小于K都是可以直接判“No”的
code:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream>
using namespace std;
#define SIZE 1000
#define INF 2147483647
typedef long long LL;
const int MAX_V=100100;
const int MAX_E=400200;
struct edge
{
int to,next;
}G[MAX_E];
int head[MAX_V],si;
int par[MAX_V],num[MAX_V];
bool vis[MAX_V];
int kk[MAX_V],N,M,K;
void add_edge(int s,int t)
{
G[si].to=t;
G[si].next=head[s];
head[s]=si++;
}
void init(int n_)
{
for(int i=0;i<=n_;i++){
par[i]=i;
num[i]=1;
}
}
int Find(int x)
{
if(par[x]==x) return x;
return par[x]=Find(par[x]);
}
void unite(int x,int y)
{
x=Find(x);
y=Find(y);
if(x==y) return ;
if(num[x]<num[y]){
par[x]=y;
num[y]+=num[x];
}
else{
par[y]=x;
num[x]+=num[y];
}
}
bool same(int x,int y)
{
return Find(x)==Find(y);
}
void solve()
{
init(N);
for(int i=1;i<=N;i++){
if(vis[i]) continue;
for(int j=head[i];j!=-1;j=G[j].next){
int mid=G[j].to;
if(vis[mid]) continue;
unite(i,mid);
}
}
for(int i=head[kk[0]];i!=-1;i=G[i].next){
int mid=G[i].to;
unite(kk[0],mid);
}
for(int i=1;i<K;i++){
for(int j=head[kk[i]];j!=-1;j=G[j].next){
int mid=G[j].to;
if(vis[mid]) continue;
unite(kk[i],mid);
}
if(!same(kk[i],kk[i-1])){
printf("No\n");
return ;
}
unite(kk[i],kk[i-1]);
for(int j=head[kk[i]];j!=-1;j=G[j].next){
int mid=G[j].to;
if(vis[mid]) unite(kk[i],mid);
}
}
printf("Yes\n");
}
int main()
{
int T,mid,s,t;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&N,&M,&K);
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
si=0;
init(N);
for(int i=0;i<K;i++) scanf("%d",&mid);
for(int i=0;i<M;i++){
scanf("%d%d",&s,&t);
add_edge(s,t);
add_edge(t,s);
unite(s,t);
}
scanf("%d",&mid);
for(int i=0;i<mid;i++){
scanf("%d",&kk[i]);
vis[kk[i]]=true;
}
if(mid<K){
printf("No\n");
continue;
}
if(num[Find(1)]!=N){
printf("No\n");
continue;
}
solve();
}
return 0;
}