【图的dfs + bitset+ 套路】hihocoder. 1041

来源:互联网 发布:php在线加密 编辑:程序博客网 时间:2024/05/17 09:20

http://hihocoder.com/problemset/problem/1041

每当我以为 dfs 我学得还可以了,就会发现自己其实对某些性质运用的并不是那么熟练
(向黑恶势力低头

其实 这题考点主要是图的dfs ,但是中间的某个步骤可以用bitset 优化一下;
题意:
给一颗树, 每条边 可以走两次,来回各一次。 给你一个遍历顺序,问是否能够按照顺序遍历。
比如:
7
1 2
1 3
2 4
2 5
3 6
3 7

如果按 3 7 2 遍历 可行, 但是按照 3 2 7 遍历则不可以,因为边只能走两次;
然后因为这题 n 比较小,所以可以强行暴力 硬A 过去。
这里讲一个O n 时间复杂度的方法,利用的就是dfs的性质

先说一个方法:

void dfs(int rot,int pre){    vis[rot][rot]=1;    for(int i=head[rot];i!=-1;i=edge[i].next){        int v=edge[i].to;        if(v==pre) continue;        dfs(v,rot);        for(int j=1;j<=n;j++){            vis[rot][j] |=vis[v][j];        }    }}

看看这个小套路 利用dfs 小性质 来完成 某些点到某些点的子树。
但这里显然是int vis[N][N] 来完成的, 不但可能开不下,而且这里还是n*n 的复杂度,谈何On 呢
这里显然就要用到 bitset,

这里 插入学习一下bitset。
可以当作一个bool型数组考虑,
bitset< N> bs; 可以考虑成一个数组bool bs[N]。

相关操作:
bs.set(); 全部置1,bs.reset()全部置0;
bs.set(pos);等价于bs[pos]=1,bs.reset(pos)等价于bs[pos]=0;

最重点的来了,bitset< N> a, b;

a和b可以直接进行操作,
!a //按位取反
a^b //按位异或
a|b //按位或
a&b //按位与
a=b<<3 //整体移位
a.count(); //a中1的个数

所以上面那段代码

void dfs(int rot,int pre){    vis[rot][rot]=1;    for(int i=head[rot];i!=-1;i=edge[i].next){        int v=edge[i].to;        if(v==pre) continue;        dfs(v,rot);        vis[rot]|=vis[v];  //因为二进制运算 这里的时间复杂度 就是常数级别    }}

然后我们知道了这个
接下来的处理方式 就仁者见仁了。

我们可以这样

void dfs2(int rot,int pre){    if(flag) return;    if(pos==m){        flag=1;        return;    }    if(rot==f[pos])        pos++;  // 走下个点    num[rot]++;  // num这点走了一次    while(pos<=m){        int cnt=pos;        for(int i=head[rot];i!=-1;i=edge[i].next){           int v=edge[i].to;           if(v==pre || num[v]) continue; //若一条路一个方向只能走一次           if(vis[v][f[pos]]){               dfs2(v,rot);            }        }       if(cnt==pos)           break;    }}

这个的精髓就在于利用的dfs 的回溯走了那一遍回来的路。
比如 3 7 2
1走到3 之后 又走到7 之后 回溯到1 又走到 2

327 的话 走完2之后 就走不了3 -7 ,因为3走过一遍。

#include<iostream>#include<stdio.h>#include<string.h>#include<math.h>#include<algorithm>#include<stdlib.h>#include<queue>#include<stack>#include<map>#include<vector>#include<bitset>#define mem(a) memset(a,0,sizeof(a))#define ll __int64#define INF 0x7fffffff   //INT_MAX#define inf 0x3f3f3f3f   //const double PI = acos(-1.0);const double e = exp(1.0);template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }using namespace std;/* * 学习一下bitset。可以当作一个bool型数组考虑,bitset<N> bs;  可以考虑成一个数组bool bs[N]。相关操作:bs.set(); 全部置1,bs.reset()全部置0;bs.set(pos);等价于bs[pos]=1,bs.reset(pos)等价于bs[pos]=0;最重点的来了,bitset<N> a, b;a和b可以直接进行操作,!a //按位取反a^b //按位异或a|b //按位或a&b //按位与a=b<<3 //整体移位a.count(); //a中1的个数*///int vis[105][105];bitset<105>vis[105];struct Edge{    int to;    int next;    int use;}edge[1000];int cnt;int head[1005];int n,m;void addedge(int u,int v){    edge[cnt].to=v;    edge[cnt].use=0;    edge[cnt].next=head[u];    head[u]=cnt++;}void dfs(int rot,int pre){    vis[rot][rot]=1;    for(int i=head[rot];i!=-1;i=edge[i].next){        int v=edge[i].to;        if(v==pre) continue;        dfs(v,rot);        vis[rot]|=vis[v];    }}int flag;int pos;int f[105];int num[105];void dfs2(int rot,int pre){    if(flag) return;    if(pos==m){        flag=1;        return;    }    if(rot==f[pos])        pos++;  // 走下个点    num[rot]++;  // num这点走了一次    while(pos<=m){        int cnt=pos;        for(int i=head[rot];i!=-1;i=edge[i].next){           int v=edge[i].to;           if(v==pre || num[v]) continue; //若一条路一个方向只能走一次           if(vis[v][f[pos]]){               dfs2(v,rot);            }        }       if(cnt==pos)           break;    }}void init(){    for(int i=1;i<=n;i++)        vis[i].reset();    memset(num,0,sizeof(num));    cnt=0;    memset(head,-1,sizeof(head));}int main() {    freopen("1.txt","r",stdin);    int cas;    scanf("%d",&cas);    while(cas--){        init();        scanf("%d",&n);        for(int i=1;i<n;i++){            int u,v;            scanf("%d %d",&u,&v);            addedge(u,v);            addedge(v,u);        }        dfs(1,0);        scanf("%d",&m);        for(int i=1;i<=m;i++){            scanf("%d",&f[i]);        }        flag=0;        pos=1;        dfs2(1,-1);        flag?printf("YES\n"):printf("NO\n");    }    return 0;}
0 0