zoj 3811 untrusted patrol
昨天網賽的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 ; }?
轉載于:https://www.cnblogs.com/kkrisen/p/3961481.html
總結
以上是生活随笔為你收集整理的zoj 3811 untrusted patrol的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TortoiseSVN菜单项功能说明
- 下一篇: 上周热点回顾(9.1-9.7)