在上一篇博客中分享了尝试用单链表修改程序,虽然在Dev上运行没有错误,但是PTA设置的测试点有几个没有通过,具体不清楚问题出现在哪里,所以现在把之前正确的程序放在这里。

7-2 深入虎穴 (30 分)
 

著名的王牌间谍 007 需要执行一次任务,获取敌方的机密情报。已知情报藏在一个地下迷宫里,迷宫只有一个入口,里面有很多条通路,每条路通向一扇门。每一扇门背后或者是一个房间,或者又有很多条路,同样是每条路通向一扇门…… 他的手里有一张表格,是其他间谍帮他收集到的情报,他们记下了每扇门的编号,以及这扇门背后的每一条通路所到达的门的编号。007 发现不存在两条路通向同一扇门。

内线告诉他,情报就藏在迷宫的最深处。但是这个迷宫太大了,他需要你的帮助 —— 请编程帮他找出距离入口最远的那扇门。

输入格式:

输入首先在一行中给出正整数 N(<),是门的数量。最后 N 行,第 我行(1)按以下格式描述编号为 i 的那扇门背后能通向的门:

  1. K D[1] D[2] ... D[K]

其中 K 是通道的数量,其后是每扇门的编号。

输出格式:

在一行中输出距离入口最远的那扇门的编号。题目保证这样的结果是唯一的。

输入样例:

  1. 13
  2. 3 2 3 4
  3. 2 5 6
  4. 1 7
  5. 1 8
  6. 1 9
  7. 0
  8. 2 11 10
  9. 1 13
  10. 0
  11. 0
  12. 1 12
  13. 0
  14. 0

输出样例:

  1. 12
    根据题目要求和输入形式,分析数据存储结构,跟树结构相似,所以采用二叉树知识进行解题。
    每行序号表示门序号,然后是这个门后面通向其他门个数,再来输入通向那些门。所以这个结构就像一个节点,然后它的孩子个数,跟树结构很像。
  1. #include<iostream>
  2. #include<queue>
  3. using namespace std;
  4.  
  5. typedef struct //结构体数组,一个数据域存放门数量,另外用一个指针指向存放通道门序号的数组
  6. {
  7. int doors;//门的数量
  8. int *p; //指向后面门的编号序列
  9. }node;
  10.  
  11. int input(node *a,int n)//读入n扇门的信息 ,并返回跟所在门序号(下标)
  12. {
  13. int i,j;
  14. bool *vi;
  15. vi=new bool[n+];//找出根结点的辅助数组
  16.  
  17. for(i=;i<n+;i++)
  18. vi[i]=false;
  19.  
  20. for(i=;i<n+;i++)
  21. {
  22. cin>>a[i].doors;
  23. if(a[i].doors)//门后面有通道
  24. {
  25. a[i].p=new int[a[i].doors];//申请存储门后面通道
  26. for(j=;j<a[i].doors;j++)
  27. {
  28. cin>>a[i].p[j];
  29. vi[a[i].p[j]]=true;
  30. }
  31. }
  32. else //door后面没有通向其他门的通道
  33. {
  34. a[i].p=NULL;
  35. }
  36.  
  37. }
  38. for(i=;i<n+;i++)//找出根结点所在下标(起点)
  39. {
  40. if(!vi[i]) return i;
  41. }
  42. }
  43.  
  44. int level(node *a,int r)//从a[r]开始对a数组进行层次遍历,并返回遍历最后一个结点的序号
  45. {//跟二叉树层次遍历相似,找到最远的门,也就是层次遍历最后的那个叶结点
  46. queue<int> q;
  47. int f,i;
  48. q.push(r);
  49.  
  50. while(!q.empty())
  51. {
  52. f=q.front();
  53. q.pop();
  54.  
  55. if(a[f].doors) //t号门后面有通道门
  56. {
  57. for(i=;i<a[f].doors;i++)
  58. {
  59. q.push(a[f].p[i]);
  60. }
  61. }
  62. }
  63. return f;//遍历到最后一个门序号,即是深度最大叶结点
  64. }
  65.  
  66. int main()
  67. {
  68. node *a;//用于存储整棵树
  69. int n,root;
  70. cin>>n;
  71. a=new node[n+];
  72. root=input(a,n);
  73. // cout<<root;
  74. cout<<level(a,root);
  75. return ;
  76. }
7-1 树的同构 (30 分)

给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。

例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。

图1                图2

现给定两棵树,请你判断它们是否是同构的。

输入格式:

输入给出2棵二叉树树的信息。对于每棵树,首先在一行中给出一个非负整数N (≤),即该树的结点数(此时假设结点从0到N−1编号);随后N行,第i行对应编号第i个结点,给出该结点中存储的1个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出“-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。

输出格式:

如果两棵树是同构的,输出“Yes”,否则输出“No”。

输入样例1(对应图1):

  1. 8
  2. A 1 2
  3. B 3 4
  4. C 5 -
  5. D - -
  6. E 6 -
  7. G 7 -
  8. F - -
  9. H - -
  10. 8
  11. G - 4
  12. B 7 6
  13. F - -
  14. A 5 1
  15. H - -
  16. C 0 -
  17. D - -
  18. E 2 -

输出样例1:

  1. Yes

输入样例2(对应图2):

  1. 8
  2. B 5 7
  3. F - -
  4. A 0 3
  5. C 6 -
  6. H - -
  7. D - -
  8. G 4 -
  9. E 1 -
  10. 8
  11. D 6 -
  12. B 5 -
  13. E - -
  14. H - -
  15. C 0 2
  16. G - 3
  17. F - -
  18. A 1 4

输出样例2:

  1. No
  2. 这道题再次用到查找树的根结点的函数,跟之前完全一样,主要实现操作在于判断树同构的算法。
    有以下几种情况:
    1、两棵树为空,则同构
    2、有一棵树为空,则不同构
    3、都不为空,但是根结点名称不同,则不同构
    4、都不为空,同构时的符合情况:
      1)左1=左2 1=右2
      2)左1=右2 1=左2
    4步判断操作可以基于前面3点,用递归方式实现。
  1. #include<iostream>
  2. #include<queue>
  3. using namespace std;
  4.  
  5. typedef struct
  6. {
  7. char name;
  8. int l,r;
  9. } node;
  10.  
  11. int BuildTree(node T[]) //建立二叉树
  12. {
  13. int i,N;
  14. bool check[]={false};//check数组用于查找树的根节点
  15. char x,y;
  16. cin>>N;
  17.  
  18. if(N)//树结点个数不为0
  19. {
  20. for(i=;i<N;i++)
  21. {
  22. cin>>T[i].name>>x>>y;
  23.  
  24. if(x!='-')//若结点不为空,将节点索引放入左子树结点
  25. {
  26. T[i].l=x-'';
  27. check[T[i].l]=true;//记录此结点索引,在check数组将该位置置为true
  28. }
  29. else
  30. {
  31. T[i].l=-;//若结点为空,将其置为-1
  32. }
  33.  
  34. if(y!='-')//同上,放入右子树
  35. {
  36. T[i].r=y-'';
  37. check[T[i].r]=true;
  38. }
  39. else
  40. {
  41. T[i].r=-;
  42. }
  43. }
  44. for(i=;i<N;i++)//遍历check数组,除了根结点之外,其它元素为true或-1
  45. {
  46. if(!check[i]) return i;//返回根结点下标
  47. }
  48. }
  49. else return -;// 若树为空,返回 -1
  50.  
  51. }
  52.  
  53. int treetonggou(node t1[],node t2[],int x,int y)//判断两棵树是否同构
  54. {
  55. if(x==-&&y==-) return ;//两棵树为空,同构
  56. else if(x==-||y==-) return ;//有一棵树为空,不同构
  57. else if(t1[x].name!=t2[y].name) return ;//根结点名称不同,不同构
  58. else//递归判断所在根结点是否符合
  59. {
  60. return((treetonggou(t1,t2,t1[x].l,t2[y].l))&&(treetonggou(t1,t2,t1[x].r,t2[y].r))//判断两棵树此结点情况:左=左并且右=右
  61. ||(treetonggou(t1,t2,t1[x].l,t2[y].r))&&(treetonggou(t1,t2,t1[x].r,t2[y].l)));//左=右并且右=左
  62. }
  63. }
  64.  
  65. int main()
  66. {
  67. node t1[],t2[];
  68. int r1,r2;
  69. r1=BuildTree(t1);
  70. r2=BuildTree(t2);//cout<<r1<<" "<<r2;
  71. //cout<<treetonggou(t1,t2,r1,r2);
  72. if(treetonggou(t1,t2,r1,r2)) cout<<"Yes";
  73. else cout<<"No";
  74. return ;
  75. }

做这道题开始不是很顺利,问题出在我用递归方式不对,在第4步时候是这样的:

  1. int treetonggou(node t1[],node t2[],int x,int y)
  2. {
  3. if(x==-&&y==-) return ;
  4. else if(x==-||y==-) return ;
  5. else if(t1[x].name!=t2[y].name) return ;
  6. else
  7. {
  8. if((treetonggou(t1,t2,t1[x].l,t2[y].l))&&(treetonggou(t1,t2,t1[x].r,t2[y].r)))
  9. return
  10. if((treetonggou(t1,t2,t1[x].l,t2[y].r))&&(treetonggou(t1,t2,t1[x].r,t2[y].l)));
  11. return
  12. }
  13. }

看是用了递归函数,之后一分析,其实没有用到前面基础进行递归,而是有自己的返回值了,没有用到递归的思想,在几个测试点没通过,因为没有考虑到各种情况,比如:

遍历结果相同,但树不同构;孩子结点相同,但根结点不同,树不同构。

之后几次修改,得到上面那个很长的return语句,最后通过。

PTA 深入虎穴 (正解)和树的同构的更多相关文章

  1. pta 编程题6 树的同构

    其它pta数据结构编程题请参见:pta 题目请参见:树的同构 因题目中左右子树是按照下标给出,因此用数组存放树是更好的方法. 判断两棵树是否同构:用递归的方法.如果当前两个结点都为空,则返回TRUE: ...

  2. HDU 4251 --- 主席树(划分树是正解)

    题意:查询区间中位数 思路:模板题,相当于区间第K大的数,主席树可以水过,但划分树是正解.但还没搞明白划分树,先上模板 #include <iostream> #include <c ...

  3. BZOJ3110 K大数查询 【线段树 + 整体二分 或 树套树(非正解)】

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c 如果是2 a b c形式,表示询问从第a个位置到第b个位 ...

  4. PTA 03-树1 树的同构 (25分)

    题目地址 https://pta.patest.cn/pta/test/15/exam/4/question/711 5-3 树的同构   (25分) 给定两棵树T1和T2.如果T1可以通过若干次左右 ...

  5. PTA 树的同构 (25分)

    PTA 树的同构 (25分) 输入格式: 输入给出2棵二叉树树的信息.对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N−1编号):随后N行,第i行对应编号第 ...

  6. 【BZOJ-4059】Non-boring sequences 线段树 + 扫描线 (正解暴力)

    4059: [Cerc2012]Non-boring sequences Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 440  Solved: 16 ...

  7. CodeForces - 633H :Fibonacci-ish II(正解:莫对+线段树)

    Yash is finally tired of computing the length of the longest Fibonacci-ish sequence. He now plays ar ...

  8. 【PTA】浙江大学数据结构慕课 课后编程作业 03-树1 树的同构

    题目内容 给定两棵树T1和T2.如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是"同构"的.例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A.B.G的左右 ...

  9. [刷题] PTA 03-树1 树的同构

    程序: 1 #include <stdio.h> 2 #define MaxTree 10 3 #define ElementType char 4 #define Tree int 5 ...

随机推荐

  1. 关于ArrayList的5道面试题

    我以面试官的身份参加过很多Java的面试,以下是五个比较有技巧的问题,我发现有些初级到中级的Java研发人员在这些问题上没有完全弄明白,似懂非懂.所以我写了一篇相关的文章,帮助初级Java研发人员弄清 ...

  2. Jmeter运行后出现乱码

    1.响应结果出现乱码一般是编码的问题,汉子乱码在编码处编码写成utf-8 2.如果还不行,对jmeter的文件进行修改.具体修改方法参考https://blog.csdn.net/liu5781821 ...

  3. switch窗口句柄

    Set<String> windows = browser.getWebDriver().getWindowHandles(); //获得所有窗口句柄 for (String string ...

  4. 在MFC中通过访问IP地址下载文件到本地

    void CDownLoad::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); UpdateData(TRUE); CStri ...

  5. 网络流解线性规划问题 BZOJ1061: [Noi2008]志愿者招募

    线性规划定义: 在给定有限的资源和竞争约束情况下,很多问题都可以表述为最大化或最小化某个目标.如果可以把目标指定为某些变量的线性函数,而且如果可以将资源约束指定为这些变量的等式或不等式,则得到了一个线 ...

  6. linux yum命令 使用

    yum -y install 包名(支持*) :自动选择y,全自动 yum install 包名(支持*) :手动选择y or n yum remove 包名(不支持*) rpm -ivh 包名(支持 ...

  7. OutputStream与PrintWriter的使用与区别

    1.OutputStream 使用步骤: 获取输出流 设置中文 将字符串转换成字节数组 调用outputStream.write() 这里只贴出doGet方法的内容: protected void d ...

  8. Shell脚本的三种执行方式

    Shell脚本的执行方式可以有以下几种: 方式一:  ./script.sh # 利用小数点来执行 方式二:  sh script.sh 或 bash script.sh # 利用bash(sh)来执 ...

  9. 《Thinking in Android 9.0 系统开发源码钻研录》

    最近打算把个人站点的博客文章同步到"博客园"! Thinking in Android -- "系统启动" [启动阶段] [相关文章] 状态 源码版本 init ...

  10. ABP入门系列目录——学习Abp框架之实操演练

    ABP是"ASP.NET Boilerplate Project (ASP.NET样板项目)"的简称. ASP.NET Boilerplate是一个用最佳实践和流行技术开发现代WE ...