传送门:hihocoder 1041
给定一棵树,从节点1出发。现在要求一种遍立方法,使得所有边都来回各走一遍,问在这种条件下是否能按指定顺序访问部分点
比较巧妙的dfs深搜。默认1为根节点,因此从1节点出发,预处理出每个节点的子树中能达到的节点。然后进行深搜,深搜策略如下:
对根节点开始,若找到某一个子节点能到达目标节点,且走向该节点的路径没有访问过,则走向子节点继续深搜直至按指定顺序访问完所有节点,或者某一节点已不可达
/****************************************************** * File Name: 1041.cpp * Author: kojimai * Create Time: 2014年10月31日 星期五 12时43分10秒 ******************************************************/ #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<iostream> #include<bitset> using namespace std; #define FFF 105 int a[FFF],first[FFF],e,cnt = 0,num,next[FFF*2],v[FFF*2]; bitset<FFF> shao[FFF];//用bitset来存每个节点的子节点中能到达点的情况 bool vis[FFF*2],ans; void addedge(int x,int y) { v[e] = y;next[e] = first[x];first[x] = e++; v[e] = x;next[e] = first[y];first[y] = e++; } void solve_can(int now,int fa)//处理出now节点的子树中能到达的点 { shao[now][now] = 1;//首先自身能到达自身位置 for(int k = first[now]; ~k;k = next[k]) { int val = v[k]; if(val == fa) continue; solve_can(val,now);//找出子节点的子树中能到达的点 shao[now] |= shao[val];//子节点能到达的点,当前点也能到,用bitset处理可以直接用或运算比较快捷 } return; } void solve(int now,int fa) { if(now == a[cnt])//访问到指定顺序的点,则准备访问下一个点 { cnt++; } if(cnt == num) { ans = true;//所有点都访问完了,则说明最后可行 return; } while(cnt < num) { int tmp = cnt; for(int k = first[now]; ~k;k = next[k]) { int val = v[k]; if(val == fa) continue; if(shao[val][a[cnt]] && !vis[k])//目标点可达且该条路没有访问过,则向下深搜 { vis[k] = true;//标记路径已经访问过 solve(val,now); break; } } if(tmp == cnt)//假如当前节点无法到达指定顺序的点或者路径已访问过不能走则返回父节点继续深搜 break; } return; } int main() { int keng; scanf("%d",&keng); while(keng--) { ans = false; int x,y; memset(first,-1,sizeof(first)); e = 0; int n; scanf("%d",&n); for(int i = 1;i < n;i++) { scanf("%d%d",&x,&y); addedge(x,y); } scanf("%d",&num); for(int i = 0;i < num;i++) scanf("%d",&a[i]); for(int i = 1;i <= n;i++) shao[i].reset(); solve_can(1,-1);//预处理每个点的子树能到达哪些点 memset(vis,false,sizeof(vis)); cnt = 0;//记录按顺序已经访问到第几个点 solve(1,-1); if(ans) printf("YES\n"); else printf("NO\n"); } return 0; }
原文地址:http://blog.csdn.net/u010535824/article/details/40652865