北邮OJ-109. 中序遍历树-11网研上机C

算法分析:

本题说是树,其实仔细分析完应当使用无向图进行建模,然后对该图进行限制性的深度优先遍历。

Debug记录:(见代码注释)
  1. 没有使用visited标记,出现了两个结点互相访问,死循环
  2. 遍历边表的时候应当使用循环尽力搜,知道找到第一个没有visited的结点才是真正的首个子节点,否则是父节点
  3. 每调用一次inOrder之前都得重置visited
  4. 用引用传参来返回子函数结果很不好!在循环中反复调用的话,一忘记初始化就gg,以后尽量用return。

题目描述
给一棵树,你可以把其中任意一个节点作为根节点。每个节点都有一个小写字母,中序遍历,得到一个字符串,求所有能得到的字符串的字典序最小串。因为这棵树不一定是二叉树,所以中序遍历时,先中序遍历以节点序号最小的节点为根的子树,然后再遍历根节点,最后根据节点序号从小到大依次中序遍历剩下的子树。

HINT

意思就是请枚举所有的点为根,然后中序遍历
最后输出所有结果中字典序最小的
比如说第二组数据
以0为根时结果为 bacd
以1为根时结果为 cadb

以2为根时结果为 badc
以3为根时结果为 bacd
所以字典序最小的是bacd

输入格式
多组数据,以EOF结束。

第一行一个数n(0< n < =100),表示树的节点的个数,节点从0开始。

然后一个长度为n的串,第i(0< = i < n)个字符表示节点i的字符。
接下来n-1行,每行两个数a,b,(0< = a,b < n),表示a和b之间有一条无向边。

输出格式
题中要求的最小的字符串

输入样例
3
bac
0 1
1 2
4
abcd
0 1
0 2
0 3
输出样例
bac
bacd

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define MAXSIZE 300 //最大顶点数 
using namespace std;
struct Edge{
    int end;
    Edge(){
    }
    Edge(int end){
        this->end=end;
    }
    bool operator<(const Edge e)const{
        return end<e.end;
    }
}; 

struct Vex{
    char data;
    Vex(){
    } 
    Vex(char data){
        this->data=data;
    }
};
struct Set{ //UnionFindSet 从0开始 
    int setSize;
    vector<Edge> edge[MAXSIZE];
    vector<Vex> vex;
    bool visited[MAXSIZE];
    int initSet(int setSize){
        this->setSize=setSize;
        for (int i=0;i<setSize;i++){
            edge[i].clear();
        }
        vex.clear();
        initVisited();
    }
    void initVisited(){
        for (int i=0;i<setSize;i++){
            visited[i]=false;
        }
    }
    void inOrder(string &s,int root){
        if (0<=root&&root<vex.size()&&visited[root]==false){//实质上为无向图的DFS,但由于是一棵树,不可能存在回环,
        //故只需满足树的遍历入口即指针非空即可,       
        //必须要判visited!否则会出现父子结点相互回访死循环!/*bug1*/
            //traverse
            int p=0; 
            visited[root]=true;
            for (p=0;p<edge[root].size();p++){//遍历边表,为了保证不会将其父节点错认为是第一个子节点 /*bug2*/
                if (visited[edge[root][p].end]==false){
                    inOrder(s,edge[root][p].end);
                    break;
                }
            }
            //visit
            s+=vex[root].data;
            //traverse
            for (;p<edge[root].size();p++){
                inOrder(s,edge[root][p].end);
            }
        }
    }
};
int main(){
    int n;
    char datas[200];
    Set set;
    int x,y;
    while (scanf("%d",&n)!=EOF){
        //initiate
        set.initSet(n);
        //input
        scanf("%s",datas);
        for (int i=0;datas[i]!='\0';i++){
            set.vex.push_back(Vex(datas[i]));
        }
        for (int i=0;i<n-1;i++){
            scanf("%d%d",&x,&y);
            set.edge[x].push_back(Edge(y));
            set.edge[y].push_back(Edge(x));
        }
            //sort edges
        for (int i=0;i<n;i++){
            sort(set.edge[i].begin(),set.edge[i].end());
        }
        //process
        string s1="",s2="";
        set.inOrder(s1,0);
        for (int i=1;i<n;i++){
            //initiate
            set.initVisited();/*bug3*/
            s2="";/*bug4*/
            set.inOrder(s2,i);
            if (s2<s1){
                s1=s2;
            }
        }
        //output
        cout<<s1<<endl;
    }
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值