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

来源:互联网 发布:单片机如何控制12v电机 编辑:程序博客网 时间:2024/05/16 17:13

我都不知道 是不是只要会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;}
0 0
原创粉丝点击