CodeForces 29 DAnt on the Tree, 超经典 裸dfs(序)

我都不知道 是不是只要会dfs 就能写这题了,真是醉了。 我还去想着用lca 做,虽然可能解出来,但只要把n变大到10000 就GG。
然后dfs序,感觉自己现在毛皮都没有掌握, 只会套用现成的固定的东西算什么会啊, 思维也被算法的框架给限制住了,这真的是一个很可怕的事情,希望我能够明白,算法毕竟是算法,思维才是最重要的东西。 有了思维,有很多很多的算法来解决你的需求,甚至可以写出很简单的代码完成需求。

学习了这位大牛的代码http://blog.csdn.net/lvshubao1314/article/details/43239901

题意:
给一棵树,然后给你一个排列 : 是所有的叶子节点的排列。 然后问你能否在每条边只走两次的情况下,能否完成树的遍历,并把点的顺序记录下来输出。

我们可以知道每条边走两次(也就是一共有 n-1 条边,每条边走两次 2*n-2 每条边u,v其实只记录一个点v ,但是根节点1 开始要记录一次,所以 容器里面一共应该是 2 * n-1个点),利用这个我们可以直接判断能否遍历

最巧妙的地方是 如何运用dfs。
众所周知dfs ,如果你要记录点,你只能先记录dfs 时间戳最深的点, 除非你进入一个dfs就记录一个,
但是!!! 如果这样会记录很多错误的点,比如从根节点1 到 目标节点 end 有很多其他路径都会走,那么会记录很多其他的点。 所以我们只能先判断是不是能到达目标节点,然后再记录。 这样我们能记录的点就会反向, 从 end……….1 , 那我们怎么办呢?

所以我们干脆 反向dfs ,从end 开始 dfs到1, 这样 反*反=正,我们记录的就是正向的一个顺序了, 自己没想到这一层,感觉我自己根本没有完完全全的掌握dfs。弱啊!


/* _ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \\| |// `. / \\||| : |||// \ / _||||| -:- |||||- \ | | \\\ - /// | | | \_| ''\---/'' | | \ .-\__ `-` ___/-. / ___`. .' /--.--\ `. . __ ."" '< `.___\_<|>_/___.' >'"". | | : `- \`.;`\ _ /`;.`/ - ` : | | \ \ `-. \_ __\ /__ _/ .-` / / ======`-.____`-.___\_____/___.-`____.-'====== `=---=' ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 佛祖保佑 永无BUG */
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#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; }
bool cmpbig(int a,int b){return a>b;}
bool cmpsmall(int a,int b){return a<b;}
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
const int MAXN=100005;

vector<int> edge[310];
vector<int> ans;

bool dfs(int root,int u,int pre){
      if(u==root){
// printf("%d =%d\n",u,root);
          return 1;
      }
      for(int i=0;i<edge[u].size();i++){
            int v=edge[u][i];
            if(v==pre) continue;
// ans.push_back(v); 如果这条路找不到 那你难道还要加进来吗
            if(dfs(root,v,u)){   // 如果找到了就停止
                ans.push_back(u);              // 正因为前面是从叶子走到跟,所以这里记录u
                return 1;
            }
      }
      return 0;
}
void init(int n){
    for(int i=1;i<=n;i++)
        edge[i].clear();
    ans.clear();
}
void addedge(int a,int b){
    edge[a].push_back(b);
    edge[b].push_back(a);
}
int f[MAXN];
int main(){
      // freopen("1.txt","r",stdin);
        int n,i;
        scanf("%d",&n);
        init(n);
        for( i=1;i<n;i++){
            int a,b;
            scanf("%d %d",&a,&b);
            addedge(a,b);
        }
        int root=1;
        ans.push_back(1);
        for(int i=2;i<=n;i++){
            if(edge[i].size()==1){
                int u;
                scanf("%d",&u);
// dfs(u,root,-1); 起点为1 是正向走,但dfs只能反向记录,即:先记录最深的点
                dfs(root,u,-1);  // 所以 我们自然要反着来
                root=u;
            }
        }
        dfs(root,1,-1);
        if(ans.size()!=2*n-1) //如果 容器里面的点数超过2*n-1
            printf("-1\n");
        else{
            for(int i=0;i<ans.size();i++){
                printf("%d ",ans[i]);
            }
        }

   return 0;
}

你可能感兴趣的:(DFS,codeforces)