题意
有n个点,其中有m个点是铁矿,k个点是煤,从1号点出发,你可以派一些士兵跑向不同的点,问占领至少一个铁矿和一个煤的时候,最少需要占领多少个点。
思路
建两幅图,其中一幅是正向边,一幅是反向边。做三次BFS。
第一遍BFS:从1号点BFS一遍整个正向边的图,记录数组dis[0][i]为每个点距离1号点的距离。O(n) 第二遍BFS:从每个铁矿BFS一遍整个反向边的图,记录数组dis[1][i]为每个点距离每个铁矿的最近距离。O(n) 第三遍BFS:从每个煤BFS一遍整个反向边的图,和第二遍类似。 对于每个点,三个dis数组求和就是从一号点到最近的铁矿和最近的煤的距离和。#includeusing namespace std;const int N = 1e5 + 10;const int INF = 0x3f3f3f3f;vector g[2][N];int o[N], c[N], b[2] = {1, 1}, dis[3][N];void bfs(int e, int n, int p[], int id) { queue que; while(!que.empty()) que.pop(); memset(dis[id], INF, sizeof(dis[id])); for(int i = 1; i <= n; i++) que.push(p[i]), dis[id][p[i]] = 0; while(!que.empty()) { int u = que.front(); que.pop(); for(int i = 0; i < g[e][u].size(); i++) { int v = g[e][u][i]; if(dis[id][v] != INF) continue; dis[id][v] = dis[id][u] + 1; que.push(v); } }}int main() { int n, m, k; scanf("%d%d%d", &n, &m, &k); for(int i = 1; i <= m; i++) scanf("%d", &o[i]); for(int i = 1; i <= k; i++) scanf("%d", &c[i]); for(int i = 0; i < 2; i++) for(int j = 1; j <= n; j++) g[i][j].clear(); for(int i = 1; i <= n; i++) { int a; scanf("%d", &a); for(int j = 1; j <= a; j++) { int v; scanf("%d", &v); g[0][i].push_back(v); g[1][v].push_back(i); } } bfs(0, 1, b, 0); bfs(1, m, o, 1); bfs(1, k, c, 2); int ans = INF; for(int i = 1; i <= n; i++) { // printf("%d : %d - %d - %d\n", i, dis[0][i], dis[1][i], dis[2][i]); if(dis[0][i] == INF || dis[1][i] == INF || dis[2][i] == INF) continue; ans = min(ans, dis[0][i] + dis[1][i] + dis[2][i]); } if(ans == INF) puts("impossible"); else printf("%d\n", ans); return 0;}