题意:
有N个城市,M条路。有K个传感器,分布在给定的K个城市中。传感器只会在第一次到达该城市时触发。现在给出L个传感器触发的先后顺序,问是否有方案遍历完所有的城市。
解析:
看了网络上面的题解,有三个条件要判断
第一点:
如果触发的传感器的数量少于传感器的总数量,那么一定没有遍历完所有城市。(即L == K)第二点:
整个图必须是连通的,要不然总会有一个点无法访问。(这个可以用并查集判断)第三点:
对于没有放传感器 或者 传感器已经触发的城市,我们的访问次数的无限制的。所以,我们这些城市的访问顺序是没有先后的,可以按照任意的顺序访问任意多次。
现在问题的关键就是:能不能按照触发顺序访问完放置传感器的城市。我们可以有以下的思路:
设定一个 已经走过城市的集合
对于每个放置传感器的城市,我们可以通过搜索得到从当前传感器出发,不触发任何传感器且能到达的城市。
同时,这些城市中如果有一个和前面已经走过的城市的集合相连的路,那就可以得到一条路,按照传感器的触发顺序,到达前一个城市。
之后将该城市加入到已经走过的城市的集合,即可以无限次访问的该集合内的任意城市。如果找不到,那就说明无法到达前一个城市。
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
set<int> st;
int n, m, K, L; //节点数,边数,传感器数,顺序
bool vis[N], sensor[N];
vector<int> g[N];
int pa[N]; //并查集,判断联通
int order[N]; //访问顺序
void init() {
memset(vis, 0, sizeof(vis));
memset(sensor, 0, sizeof(sensor));
st.clear();
for(int i = 0; i < N; i++) {
g[i].clear();
pa[i] = i;
}
}
void add(int from, int to) {
g[from].push_back(to);
}
int find(int x) {
return (x == pa[x]) ? x : pa[x] = find(pa[x]);
}
void Union(int a, int b) {
int r1 = find(a), r2 = find(b);
if(r1 == r2) return;
if(r1 < r2) pa[r2] = r1; else pa[r1] = r2;
}
bool bfs(int star) {
queue<int> que;
st.insert(star);
for(int i = 1; i <= L; i++) {
if(st.count(order[i])) {
que.push(order[i]);
vis[order[i]] = true;
while(!que.empty()) {
int u = que.front();
que.pop();
for(int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if(vis[v]) continue;
vis[v] = true;
if(sensor[v]) st.insert(v);
else que.push(v);
}
}
}else return false;
}
return true;
}
bool judge() {
int u, v;
bool ok = true;
while(m--) {
scanf("%d%d", &u, &v);
add(u, v);
add(v, u);
Union(u, v);
}
//利用并查集判断所有的点是否联通
for(int i = 2; i <= n; i++)
if(find(pa[1]) != find(pa[i])) {
ok = false; break;
}
scanf("%d", &L);
if(L != K) ok = false;
//输入访问顺序
for(int i = 1; i <= L; i++)
scanf("%d", &order[i]);
//如果bfs失败
if(!bfs(order[1])) ok = false;
return ok;
}
int main() {
int T, x;
scanf("%d", &T);
while(T--) {
init();
scanf("%d%d%d", &n, &m, &K);
//标记传感器
for(int i = 0; i < K; i++) {
scanf("%d", &x);
sensor[x] = true;
}
printf("%s\n", judge() ? "Yes" : "No");
}
return 0;
}