zoj 3811 untrusted patrol

拜拜、爱过 提交于 2020-03-27 17:31:39

昨天网赛的C题,我负责的,题意有些模模糊糊的

我首先弄清楚了题意,即要求一个patrol是否可能巡视过所有的点,首先整个图要是连通的,这个在建图的时候边用下并查集即可,然后某些点装了传感器,传感器应该要全部都响应过才行,即L==k否则直接输出No,然后就是重点,给出的传感器的响应先后顺序,我们要在图上找到这样一种路径,路径上的传感器的先后顺序正好对应了给出的记录,找不到则是No,找到了就是Yes。

我一开始看到点有10万个,想用DFS+回溯尝试每种路径,最多20W条的路,但是路径种树就远远不止了。。所以抱着尝试的心态,这样的子TLE了就知道不是这种方法了。

后来就是我坑了,聪哥想了一种BFS的方法,只要对所有点遍历一遍即可,我听了两遍才搞清楚,而且还歪曲了其中一个重要的思想,导致第一次敲出的BFS还WA了一发。他给我讲完之后,我理解的思路是从传感器的第一个出发,往下进行搜索,是普通点就vis掉加入队列,是我们当前要找的下一个传感器就也vis掉加入队列,并且把一个cur标记++,这样如果存在这样的路径,最后的cur就==k,然后这种方法其实是错的,这就是我忽略了聪哥给我讲的思想的重要一点,因为题目里面传感器是只记录第一次到达的时间,所以可以来回走,这么说的话,我要找的传感器的序列 不一定要是真的存在一条路径上,只要走回之前的点,能找到下一个新的传感器也是合理的

。。。

所以这就不能用普通的找路径的BFS了,我用个染色标记,记录当前传感器是否已经被访问过,首先把第一个传感器标记,并且打入队列,然后走一遍BFS,把所有可以访问到的传感器都染色一下,但不入队列,之后又对下一个传感器首先判断是否被染过色,染过就入队列,像刚刚一样,BFS,把之后可能遍历到的传感器又染色。。如果我下一个要进队列的传感器没有被染过色,直接return false,因为说明肯定没有这样的路径能直接进入下一个传感器。。。如果整个能一套走完就返回true

这样子BFS首先保证了传感器的访问顺序严格按要求,中间不会插入其他传感器,并且因为我每次把当前传感器 ,对之后可能遍历到的传感器都染色,这样对于来回走的情况也考虑到了,不会漏情况

之前聪哥给我讲的时候,没领会这个重要思想,弄得搞半天才出来。这个怪我。而且这个其实应该容易想到,至少我上面那种错误的BFS方法要可以想的到,居然在那里呆了好久,都没想到。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N = 100010;
int n,m,k,L;
int order[N];
int inq[N];
vector<int> G[N];
int fa[N];
int vis[N];
int a,b;
int findset(int x)
{
    if (x!=fa[x]){
        fa[x]=findset(fa[x]);
    }
    return fa[x];
}
bool bfs()
{
    queue<int> q;
    vis[order[0]]=1;
    for (int i=0;i<L;i++){
        if (vis[order[i]]) q.push(order[i]);
        else return false;
        while (!q.empty())
        {
            int u=q.front();
            q.pop();
            for (int i=0;i<G[u].size();i++){
                int v=G[u][i];
                if (inq[v]) vis[v]=1;
                else
                {
                    if (vis[v]) continue;
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return true;
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for (int i=0;i<=n;i++){
            G[i].clear();
            fa[i]=i;
            vis[i]=0;
            inq[i]=0;
        }
        for (int i=0;i<k;i++){
            scanf("%d",&order[i]);
            inq[order[i]]=1;
        }
        while (m--)
        {
            scanf("%d%d",&a,&b);
            G[a].push_back(b);
            G[b].push_back(a);
            int r1=findset(a);
            int r2=findset(b);
            if (r1!=r2) fa[r1]=r2;
        }
        scanf("%d",&L);
        for (int i=0;i<L;i++) scanf("%d",&order[i]);
        if (L<k){
            puts("No");
            continue;
        }
        int rt=findset(n);
        bool flag=1;
        for (int i=1;i<n;i++){
            if (findset(i)!=rt){
                flag=0;
                break;
            }
        }
        if (!flag) {
            puts("No");
            continue;
        }
        flag=bfs();
        if (flag) puts("Yes");
        else puts("No");
    }
    return 0 ;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!