您的位置:首页 > 其它

ZOJ - 3811 Untrusted Patrol(bfs+并查集)

2015-03-10 21:22 429 查看

题意:

有N个城市,M条路。有K个传感器,分布在给定的K个城市中。传感器只会在第一次到达该城市时触发。现在给出L个传感器触发的先后顺序,问是否有方案遍历完所有的城市。

解析:

看了网络上面的题解,有三个条件要判断

第一点:

如果触发的传感器的数量少于传感器的总数量,那么一定没有遍历完所有城市。(即L == K)


第二点:

整个图必须是连通的,要不然总会有一个点无法访问。(这个可以用并查集判断)


第三点:

对于没有放传感器 或者 传感器已经触发的城市,我们的访问次数的无限制的。所以,我们这些城市的访问顺序是没有先后的,可以按照任意的顺序访问任意多次。

现在问题的关键就是:能不能按照触发顺序访问完放置传感器的城市。


我们可以有以下的思路:

设定一个 已经走过城市的集合

对于每个放置传感器的城市,我们可以通过搜索得到从当前传感器出发,不触发任何传感器且能到达的城市

同时,这些城市中如果有一个和前面已经走过的城市的集合相连的路,那就可以得到一条路,按照传感器的触发顺序,到达前一个城市

之后将该城市加入到已经走过的城市的集合,即可以无限次访问的该集合内的任意城市。如果找不到,那就说明无法到达前一个城市。

AC代码

[code]#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
, sensor
;
vector<int> g
;
int pa
; //并查集,判断联通
int order
; //访问顺序

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: