表达式树(公共表达式消除 uva 12219)

一共写了3遍,2遍超时,第三遍看了别人的代码才写出来的。。。


第一遍,直接保存整颗子树,也就是整个子表达式。

为了得到子表达式的值,我频繁调用substr函数。

为了找到分隔左右子表达式的逗号,我直接遍历子表达式。

最后用map去映射。

结果超时。。

后来看了下紫书,说不能保存整颗子树。。

说比较两棵树的时间复杂度是O(n),循环枚举两颗子树,总时间复杂度高达O(n^3)。

我本以为map比较高效的,但后来我仔细算了下发现不会高效很多。

我们都知道map的时间复杂度是O(logn),但是那只是查询的复杂度。如果你查询的是字符串,那就多O(n),每个子树查询一遍,就又多O(n),总共O(n^2logn)。

伤不起。。。


第二遍,建树使扫描整个子表达式找到中间的那个逗号

按书上说的改了下子树的保存方式后,时间复杂度变为O(nlogn),依旧超时。

后来上网看别人的代码,才知道我建树的方法太粗暴了。频繁调运substr+遍历找逗号,都不知道循环多少遍了。

只有扫描一遍的才不会超时。


参考 http://www.bubuko.com/infodetail-646757.html


AC代码

#include
#include
#include
#include
#include
using namespace std;

string s;
int k,cnt;
mapdone;

struct tree
{
    string s;
    int ls,rs;
    bool operator < (const tree& rhs) const//要用map一定要重载运算符。
    {
        if(s!=rhs.s) return sMAP;//保存ID
mapNODE;//保存节点信息

int solve()//只扫描一遍,好棒。
{
    string cur;
    while(s[k]>='a'&&s[k]<='z') cur.push_back(s[k++]);
    int id=++cnt;//跟cnt有关的代码都好精彩,前两遍我也想到了,但写的好烂。
                 //这里是先给你预留一个编号的意思。
    tree& t=NODE[id];//引用,好灵活。
    t.s=cur;
    t.ls=0;
    t.rs=0;
    if(s[k]=='(')
    {
        //写得简单易懂,跳过非字母的字符。
        k++;
        t.ls=solve();k++;
        t.rs=solve();k++;
    }
    if(MAP[t]) {cnt--;return MAP[t];}//如果MAP[t]!=0,那么cnt必为id+1,cnt--即可取消预留的编号。
    else return MAP[t]=id;
}
//原来还可以这样输出。。。不过前两遍的代码我是一遍dfs解决建树与输出的。
//该省的不省。。不该省的乱省。。只能说自己对时间复杂度不够敏感吧。
void print(int u)
{
    if(done[u]) printf("%d",u);
    else
    {
        done[u]=1;
        cout<>q;
    while(q--)
    {
        MAP.clear();
        done.clear();
        NODE.clear();
        cnt=k=0;
        cin>>s;
        print(solve());//solve返回根编号,print从根标号开始递归输出。
        puts("");
    }
    return 0;
}


第一遍代码

#include
#include
#include
#include
using namespace std;

struct tree
{
    string now;
    int l,r;
    tree(string a,int b,int c):now(a),l(b),r(c){}
};

mapMAP;
string s;
int cnt;

void dfs(int l,int r)
{
    string a=s.substr(l,r-l+1);
    if(MAP[a]) {printf("%d",MAP[a]);return;}
    int now=++cnt;
    if(s[r]!=')') {cout<>s;
        dfs(0,s.size()-1);
        puts("");
    }
    return 0;
}

第二遍代码

#include
#include
#include
#include
#include
using namespace std;

struct tree
{
    string now;
    int l,r;
    tree(string a,int b,int c):now(a),l(b),r(c){}
    bool operator < (const tree & rhs) const
    {
        if(now!=rhs.now) return now pii;
typedef pair pis;
mapMAP;
string s;
int cnt;

pair dfs(int l,int r)
{
    if(s[r]==')')
    {
        int ll=l;
        while(s[ll]!='(') ll++;
        int k=ll;
        int p=0;
        while(1)
        {
            if(s[k]=='(') p++;
            if(s[k]==')') p--;
            if(p==1&&s[k]==',') break;
            k++;
        }
        int now=++cnt;
        string cur=s.substr(l,ll-l);
        stringstream sss;
        string ss;
        pair ls=dfs(ll+1,k-1);
        pair rs=dfs(k+1,r-1);
        //cout<<"      "<>ss;
            return make_pair(make_pair(1,ss),id);
        }
        else
        {
            sss<>ss;
            return make_pair(make_pair(0,ss),now);
        }
    }
    else
    {
        string ss=s.substr(l,r-l+1);
        tree t(ss,0,0);
        int id=MAP[t];
        stringstream sss;
        if(id) sss<>ss;
        if(id) return make_pair(make_pair(1,ss),id);
        else return make_pair(make_pair(0,ss),cnt);
    }
}

int main()
{
    int c;
    scanf("%d",&c);
    while(c--)
    {
        MAP.clear();
        cnt=0;
        cin>>s;
        cout<


你可能感兴趣的:(树,紫书-第11章-图论模型与算法)