Code the Tree(记忆化深搜构造树)

本文介绍了一种基于Prufer法则生成无根树Prufer序列的算法,并通过具体的样例展示了如何从树形结构中提取所需信息,进而计算出对应的Prufer序列。
一个树形图的所有节点已经用1,2,……n来标号。用Prufer法则来表示这样一棵树需要依据如下方法:有最小编号的叶结点将被除去。这个叶结点和它在图中与之相邻的边将会一起被除去,然后记下被除去边的另一个端点。在图上重复这个过程,直到图中只剩下一个节点(顺便说一句,剩下的肯定是编号为n的节点)。然后,你将得到一个长度为n-1的数组,这个数组便成为Prufer树。
你的任务是,对于一颗指定的树,计算并输出它的Prufer树的代码。树的形式语言由如下的方法构造:

T ::= "(" N S ")"
S ::= " "T S | empty
N ::= number

注意,对于以上的定义,这棵树的根是不确定的。任何一个顶点都有可能成为这棵树的根。通常,我们称这种树为“无根树”。

Input

输入可能有多组测试数据。每一组数据占一行,来表示一棵树。输入将以EOF结尾,每棵树的n的范围为1<=n<=50。

Output

对于每组测试数据,输出一行数字,即其对应的Prufer树。每两个数字间要有空格,但行末不要有。

Sample Input

(2 (6 (7)) (3) (5 (1) (4)) (8))
(1 (2 (3)))
(6 (1 (4)) (2 (3) (5)))                                                           

Sample Output

记忆化深搜的部分很棒,需要再学习。

[cpp]  view plain  copy
 print ?
  1. #include<iostream>    
  2. #include<algorithm>    
  3. #include<string>    
  4. #include<map>    
  5. #include<vector>    
  6. #include<cmath>    
  7. #include<queue>    
  8. #include<string.h>    
  9. #include<stdlib.h>    
  10. #include<cstdio>    
  11. #define ll long long    
  12. using namespace std;    
  13. int now,n;    
  14. int g[60][60],in[60];    
  15. int build(char* str){    
  16.     int num;    
  17.     while (now<strlen(str)){    
  18.         if (str[now] <= '9' && str[now] >= '0'){    
  19.             if (str[now+1] <= '9' && str[now+1] >= '0'){ //两位数   
  20.                 num=(str[now]-'0')*10+(str[now+1]-'0');    
  21.                 now+=2;    
  22.             }    
  23.             else{  //一位数   
  24.                 num=str[now]-'0';    
  25.                 now++;    
  26.             }    
  27.             n++;  
  28.             continue;    
  29.         }    
  30.         if (str[now] == '('){    
  31.             now++;    
  32.             int i=build(str);  //递归,记忆化深搜,找到与num相连的点   
  33.             in[num]++;  //度数+1  
  34.             in[i]++;    
  35.             g[num][i]=1;  //num和i连边   
  36.             g[i][num]=1;    
  37.         }    
  38.         else if (str[now] == ')'){    
  39.             now++;    
  40.             return num;    
  41.         }    
  42.         else if (str[now] == ' '){    
  43.             now++;    
  44.             continue;    
  45.         }    
  46.     }    
  47. }    
  48. int main(){    
  49.     int i,j,k,d;    
  50.     char str[2000];    
  51.     while (gets(str)&&str!=""){    
  52.         n=0;  
  53.         memset(in,0,sizeof(in));  
  54.     memset(g,0,sizeof(g));    
  55.         now=0;    
  56.         build(str);    
  57.         if (n == 1){    
  58.             printf("\n");    
  59.             continue;    
  60.         }   
  61.         for (i=1; i<n-1; i++){  //最后的数组是从这个树中找出n-1个点  
  62.             for (j=1; j<n; j++){  //编号从小到大  
  63.                 if (in[j] == 1){  //叶节点  
  64.                     in[j]=-1;  //删掉这个点  
  65.                     for (k=1; k<=n; k++){    
  66.                         if (g[j][k] == 1 || g[k][j] == 1){  //找出它的父节点  
  67.                             g[j][k]=0;    
  68.                             g[k][j]=0;    
  69.                             in[k]--;  //父节点度数-1  
  70.                             printf("%d ",k);    
  71.                             break;    
  72.                         }    
  73.                     }    
  74.                     break;    
  75.                 }    
  76.             }    
  77.         }    
  78.         printf("%d\n",n);    
  79.     }    
  80. }    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值