题意:在某些点上安装首次访问时候会报警的机器,给出报警嗲你的顺序,问是否合法。
思路:按所给的序列,每个进来时判断这个点目前能否达到(第一个可达总是),若能,则该点进行扩展遍历所有没有报警器的点,遇到有的报警器的标记可达就返回。
预判:判断原图连图性。
#include<iostream>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
vector<vector<int> >g(100010);
int has[100010];
vector<int>jud;
int n,m,k,l;
int vis[100010];
bool bfs()
{
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(1);
vis[1]=1;
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=0;i<g[cur].size();i++)
{
int v=g[cur][i];
if(vis[v]==0)
{
vis[v]=1;
q.push(v);
}
}
}
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
return 0;
}
}
return 1;
}
void dfs(int u)
{
if(has[u]==1&&vis[u]==0)
{
vis[u]=1;
return ;
}
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(vis[v]==0&&has[v]==0)
{
vis[v]=1;
dfs(v);
}
else if(vis[v]==0)
{
dfs(v);
}
}
return ;
}
void init()
{
for(int i=0;i<=n;i++)
{
has[i]=0;
g[i].clear();
vis[i]=0;
}
jud.clear();
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
init();
int tx,ty;
for(int i=0;i<k;i++)
{
scanf("%d",&tx);
has[tx]=1;
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&tx,&ty);
g[tx].push_back(ty);
g[ty].push_back(tx);
}
scanf("%d",&l);
for(int i=0;i<l;i++)
{
scanf("%d",&tx);
jud.push_back(tx);
}
if(l!=k||bfs()==0)
{
printf("No\n");continue;
}
memset(vis,0,sizeof(vis));
bool marks=1;
vis[jud[0]]=1;
for(int i=0;i<l;i++)
{
if(vis[jud[i]]==0)
{
marks=0;break;
}
dfs(jud[i]);
}
if(marks)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}