一些数据结构的实现

11988(uva)

意思是,你要输入一个字符串,遇到 [ 时按home键, 遇到 ] 时按end键, 然后问你最终这个字符串是什么
SampleInput
This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University
SampleOutput
BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University

这题不难用链表做,但是这个链表不是上数据结构时用指针指啊指的那种实现方式,先看代码。

#include<bits/stdc++.h>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
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;}
template<class T> inline T Min(T a, T b) {return a < b ? a : b;}
template<class T> inline T Max(T a, T b) {return a > b ? a : b;}
int n, m;

#define N 100010
char str[N];
int len;
int nxt[N];//next[i] 第i个字符的下一个字符的下标
int cur, last;

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    while(~sfs(str + 1)) {
        len = strlen(str + 1);
        mem(nxt, 0);
        cur = last = 0;
        repe(i, 1, len) {
            if(str[i] == '[') {
                cur = 0;
            }
            else if(str[i] == ']') {
                cur = last;
            }
            else {
                nxt[i] = nxt[cur];
                nxt[cur] = i;
                if(cur == last) last = nxt[cur];        //更新last的时候要注意不要简单的把last位置放在最后一个[前面
                cur = i;
            }
        }
        cur = 0;
        while(nxt[cur]) {
            putchar(str[nxt[cur]]);
            cur = nxt[cur];
        }
        enter;
    }
    return 0;
}

这里 nxt 数组差不多就是链表的指针实现的那个 next 指针了。

这种做法说白了也不难理解,但是上课的时候李冬梅却没提过,照她所说的链表,永远都是一根指针指啊指,一根不行来两根,除了线性表的数组实现和链式实现,她好像从来没有强调过一个数据结构的不同实现方法,给人一种这些数据结构只能用一种方式实现的感觉。

没错我一开始也以为一些数据结构只能有限的(就是上课说的那样)实现,但是我渐渐发现, 链表可以用个数组来代替指针,原本指针指的地址, 用一个int 类型来指下标就行了,但是本质变了吗? 没有啊, 都是通过这个 “地址” 来找到下面一项啊, 这个地址可以是指针实现, 也可以直接用个int变量实现啊, 反正只要找得到就行了嘛。 同样的还有树(二叉树, trie 树 etc), 图的邻接矩阵(为什么一定要用链表数组呢?短时间内写起来也不容易, 用起来也容易出错。)etc

我的意思并不是说上课学的实现方法不重要,但是千万别忘了数据结构的本质是数据之间的关系和数据的组织方式, 学习的时候不要拘泥于实现方式,最重要的是抓住这种数据结构的本质思想,在不同情况下灵活的实现并且使用。

老师教得死不死不重要,你得自己活学活用。

12657

一排有n个盒子(编号1 ~ n),m次操作:

1 X Y 把编号x的盒子放在y的左边(如果本来就是,则不做任何操作)

2 X Y 把编号x的盒子放在y的右边(同上)

3 X Y 把编号x和编号y的盒子换个位置

4 逆转序列

典型的双向链表(左右)。但是按照指针来实现还挺麻烦的,找X 和 Y就是 O(n)的时间, 更别说操作了。

不难(但是很细),贴代码把

#include<bits/stdc++.h>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
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;}
template<class T> inline T Min(T a, T b) {return a < b ? a : b;}
template<class T> inline T Max(T a, T b) {return a > b ? a : b;}
int n, m;

#define N 100010

struct box {
    int lf;
    int rg;
};

box bx[N];

int od, x, y;
int dir;

void link(int pox, int poy) {   //把poy位置的盒子连在pox位置的盒子的右边
    bx[pox].rg = poy;
    bx[poy].lf = pox;
}

void rm(int pos) {              //移除pos位置的盒子并维护双向链表
    link(bx[pos].lf, bx[pos].rg);
}


void Init() {                   //初始化,把链表连起来
    dir = 1;
    repe(i, 0, n) {
        bx[i].lf = i - 1;
        bx[i].rg = (i + 1) % (n + 1);
    }
    bx[0].lf = n;               //0位置相当于哨兵
}

LL counter() {                  //计数,dir : -1 表示逆序, +1 表示顺序
    LL ans = 0; int flag = 1;
    int pos = (dir == 1 ? bx[0].rg : bx[0].lf);
    while(pos) {
        if(flag % 2 == 1) ans += pos;
        pos = (dir == 1 ? bx[pos].rg : bx[pos].lf);
        flag++;
    }
    return ans;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    int cas = 0;
    while(~sfd(n, m)) {
        Init();
        while(m--) {
            sf(od);
            if(od == 4) {       //逆转操作
                dir *= -1;
            }
            else {
                sfd(x, y);
                if(dir == -1 && od != 3) od = 3 - od;   //注意, 逆转之后左右颠倒
                if(od == 1) {                           //把X放到Y左边
                    if(x == bx[y].lf) continue;
                    rm(x);                              //先移除X(把x左右互相连起来)
                    link(bx[y].lf, x);                  //连接y的左边和x
                    link(x, y);                         //连接x和y
                }
                else if(od == 2) {
                    if(x == bx[y].rg) continue;
                    rm(x);
                    link(x, bx[y].rg);
                    link(y, x);
                }
                else {
                    if(x == bx[y].lf || x == bx[y].rg) { //相邻的情况
                        if(x == bx[y].rg) { x ^= y; y ^= x; x ^= y;}    //让x在左边,统一操作
                        int l = bx[x].lf, r = bx[y].rg;
                        link(l, y); link(x, r);
                        link(y, x);
                    }
                    else {
                        int lx = bx[x].lf, rx = bx[x].rg; //不相邻的情况
                        int ly = bx[y].lf, ry = bx[y].rg;
                        link(lx, y); link(y, rx);
                        link(ly, x); link(x, ry);
                    }
                }
            }
        }
        printf("Case %d: %lld\n", ++cas, counter());       //计数输出
    }
    return 0;
}

模拟的情况复杂时,想办法提取出函数多次调用,思路要清晰。

照书上写的,这个双向链表也可以用left[N] right[N]两个数组表示, 其实也差不多

上面写了两种链表,下面写二叉树

122

(11,LL) (7,LLL) (8,R)
(5,) (4,L) (13,RL) (2,LLR) (1,RRR) (4,RR) ()
(3,L) (4,R) ()

通过这种格式(value, direction)把值按照方向插入二叉树(最多有256个结点)。然后层次遍历输出所有结点的值。如果有些结点没有值或者被重复赋值,输出not complete。

因为最多有256个结点,所以普通的数组实现(实现完全二叉树那样左子树根在2 * i + 1 又子树根在2 * i + 2)肯定不行。(如果全集中在右边,需要2 ^ 256 这么大的数组)。所以提供两种实现方法

1、 最常规的指针指(需要手动释放内存)

#include<bits/stdc++.h>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
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;}
template<class T> inline T Min(T a, T b) {return a < b ? a : b;}
template<class T> inline T Max(T a, T b) {return a > b ? a : b;}
int n, m;

char dir[10];

typedef struct Elmt {
    int value;
    struct Elmt * ls, * rs;
    bool hav;
    Elmt(int v = -1) {
        this->value = v;
        this->hav = false;
        this->ls = NULL;
        this->rs = NULL;
    }
}Tree, *Eptr;

Eptr tree;
queue<Eptr> q;
queue<int> ans;
bool failed;

void Destroy(Eptr root) {
    if(!root) return ;
    Destroy(root->ls);
    Destroy(root->rs);
    delete root;
}

void Ins(int v, char* s) {
    if(!tree) tree = new Tree();
    Eptr root = tree;
    while(*s != ')') {
        if(*s == 'L') {
            if(!root->ls) root->ls = new Tree();
            root = root->ls;
        }
        else if(*s == 'R') {
            if(!root->rs) root->rs = new Tree();
            root = root->rs;
        }
        s++;
    }
    if(root->hav) failed = true;
    root->value = v;
    root->hav = true;
}

bool Init() {
    char od[1000];
    tree = new Tree();
    failed = false;
    while(true) {
        if(sfs(od) == -1) return false;
        if(!strcmp(od,"()")) break;
        int v;
        sscanf(&od[1], "%d", &v);
        Ins(v, strchr(od, ',') + 1);
    }
    return true;
}

bool bfs() {
    while(!q.empty()) q.pop();
    while(!ans.empty()) ans.pop();
    q.push(tree);
    Eptr root = NULL;
    while(!q.empty()) {
        root = q.front(); q.pop();
        if(root->hav == false) return false;
        ans.push(root->value);
        if(root->ls) {
            q.push(root->ls);
        }
        if(root->rs) {
            q.push(root->rs);
        }
    }
    return true;
}



int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    while(Init()) {
        if(!failed && bfs()) {
            printf("%d", ans.front()); ans.pop();
            while(!ans.empty()) printf(" %d", ans.front()), ans.pop();
            enter;
        }
        else pfs("not complete");
        Destroy(tree);
    }
    return 0;
}

第二种、还是数组,不过是结构题数组,每个结点加两个整形变量表示左子树和右子树的下标

#include<bits/stdc++.h>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
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;}
template<class T> inline T Min(T a, T b) {return a < b ? a : b;}
template<class T> inline T Max(T a, T b) {return a > b ? a : b;}
int n, m;

char dir[10];
bool failed;
int cnt;

struct Tree {
    int value;
    bool hav;
    int ls, rs;
    void update(int v) {
        this->value = v;
        this->hav = false;
        this->ls = -1;
        this->rs = -1;
    }
};

Tree tree[300];
queue<int> q;
queue<int> ans;

void Init() {
    cnt = 0;
    rep(i, 0, 300) {
        tree[i].value = -1; tree[i].hav = false;
        tree[i].ls = -1; tree[i].rs = -1;
    }
    failed = false;
}

void Ins(int v, char *s) {
    int root = 0;
    while(*s != ')') {
        if(*s == 'L') {
            int ls = tree[root].ls;
            if(ls == -1) tree[++cnt].update(-1), tree[root].ls = cnt, ls = cnt;
            root = ls;

        }
        else if(*s == 'R') {
            int rs = tree[root].rs;
            if(rs == -1) tree[++cnt].update(-1), tree[root].rs = cnt, rs = cnt;
            root = rs;
        }
        s++;
    }
    if(tree[root].hav) failed = true;
    tree[root].hav = true;
    tree[root].value = v;
}

bool Input() {
    Init();
    char od[1000];
    while(true) {
        if(sfs(od) == -1) return false;
        if(!strcmp(od,"()")) break;
        int v;
        sscanf(&od[1], "%d", &v);
        Ins(v, strchr(od, ',') + 1);
    }
    return true;
}

bool bfs() {
    while(!q.empty()) q.pop();
    while(!ans.empty()) ans.pop();
    q.push(0); int root;
    while(!q.empty()) {
        root = q.front(); q.pop();
        if(!tree[root].hav) return false;
        ans.push(tree[root].value);
        if(tree[root].ls != -1) q.push(tree[root].ls);
        if(tree[root].rs != -1) q.push(tree[root].rs);
    }
    return true;
}



int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    while(Input()) {
        if(!failed && bfs()) {
            printf("%d", ans.front()); ans.pop();
            while(!ans.empty()) printf(" %d", ans.front()), ans.pop();
            enter;
        }
        else pfs("not complete");
    }
    return 0;
}

548 uva
二叉树的题,题目意思是:
输入一颗二叉树的中序遍历序列和后序遍历序列,你需要建立这棵二叉树然后求一个结点使得从根到它的路径上的结点的和最小,输出那个结点的值。(输入保证每个结点的值都不一样)(如果有多个最小值,输出结点本身值最小的那个)

Sample Input
3 2 1 4 5 7 6
3 1 2 5 6 7 4
7 8 11 3 5 16 12 18
8 3 11 7 16 18 12 5
255
255

Sample Output
1
3
255

根据中序和后序建树,然后dfs一遍就行,当然建树的时候就可以更新答案,不过代码打起来比较麻烦所以没那么做。O(n)的复杂度。代码如下:

#include<bits/stdc++.h>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
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;}
template<class T> inline T Min(T a, T b) {return a < b ? a : b;}
template<class T> inline T Max(T a, T b) {return a > b ? a : b;}
int n, m;

#define N 10010
int in[N];
int post[N];
queue<int> q;
int sum, pos;

struct Tree {
    int value;
    int ls, rs;
    void update(int v) {
        this->value = v;
        this->ls = -1;
        this->rs = -1;
    }
};
Tree tree[N];

bool read_list(int * a) {                       //读入
    n = 0;
    string line;
    if(!getline(cin, line)) return false;
    stringstream ss(line);                      //记住这种字符流的输入方法
    while(ss >> m) a[n++] = m;
    return n > 0;
}

void Init() {
    m = -1; sum = INF;
    rep(i, 1, n) tree[i].update(-1);
}

int find_root(int pos, int low, int v) {        //返回树根在中序的下标
    for(int i = pos; i >= low; i--) {
        if(in[i] == v) return i;
    }
    return -1;
}

int Build(int li, int ri, int lp, int rp) {     //建树,返回树根在tree里的下标
    if(ri < li || rp < lp) return -1;
    int root = ++m;
    tree[root].update(post[rp]);
    int nt = find_root(ri, li, tree[root].value);
    int dt = ri - nt;
    tree[root].rs = Build(nt + 1, ri, rp - dt , rp - 1);
    tree[root].ls = Build(li, nt - 1, lp, rp - dt - 1);
    return root;
}

void dfs(int root, int psum) {  //更新答案
    if(root == -1) return ;
    psum += tree[root].value;
    if(tree[root].ls == -1 && tree[root].rs == -1) {
        if(psum < sum) {
            sum = psum;
            pos = root;
        }
        else if(psum == sum) {
            pos = (tree[root].value < tree[pos].value ? root : pos);
        }
    }
    dfs(tree[root].ls, psum);
    dfs(tree[root].rs, psum);
}

void inorder(int root) {    //中序遍历,用于测试
    if(root == -1) return;
    inorder(tree[root].ls);
    printf("%d ", tree[root].value);
    inorder(tree[root].rs);
}

void postorder(int root) {  //后序遍历,用于测试
    if(root == -1) return ;
    postorder(tree[root].ls);
    postorder(tree[root].rs);
    printf("%d ", tree[root].value);
}

void check(int root) {//检测建树是否正确
    pfs("in");
    rep(i, 0, n) printf("%d%c", in[i], i == n - 1 ? '\n' : ' ');
    inorder(root); enter;
    pfs("post");
    rep(i, 0, n) printf("%d%c", post[i], i == n - 1 ? '\n' : ' ');
    postorder(root); enter;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    while(read_list(in)) {  //读中序
        read_list(post);    //读后序
        Init();             //初始化
        dfs(Build(0, n - 1, 0, n - 1), 0); //建树,dfs找答案
        pf(tree[pos].value);
    }
    return 0;
}

这题我记下来的原因是,尽管花了一点时间,但是建树的过程居然没有bug!!!居然一次就建对了!!!神奇

还有些树的题目根本不用把树建出来,各种函数的调用过程本身就能形成一棵树。

839 uva
输入一个树状天平,根据力矩相等判断天平是否平衡。(wr * dr == wl * dl)
采用先序方式输入:每个天平的格式为:wl, dl, wr, dr,当wl或者wr等于0时,表示该砝码是一个子天平, 会先描述左子天平然后再是又子天平。(注意,每个天平都需要平衡)

递归输入的时候就形成了一颗二叉树,所以不需另建。

#include<bits/stdc++.h>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
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;}
template<class T> inline T Min(T a, T b) {return a < b ? a : b;}
template<class T> inline T Max(T a, T b) {return a > b ? a : b;}
int n, m;

bool Build(int & w) {
    int wl, dl, wr, dr;
    scanf("%d%d%d%d", &wl, &dl, &wr, &dr);
    bool lf = true, rg = true;
    if(!wl) lf = Build(wl);
    if(!wr) rg = Build(wr);
    w = wl + wr;
    return lf && rg && (wl * dl == wr * dr);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    ds(t);int w;
    while(t--) {
        if(Build(w)) pfs("YES");
        else pfs("NO");
        if(t) enter;
    }
    return 0;
}

非二叉树:
297 uva
如图所示,可以用四分树来描述一个黑白图像,方法是用根结点表示整幅图像,然后把行列分成两等分,按照图中数字编号,对应4个子结点。如果某字节点全黑或全白,则直接用一个黑结点或白结点表示;如果既有黑又有白,则用一个灰结点表示。
给出两颗树的先序遍历,求二者合并后(黑色部分合并)黑色像素的个数。p表示中间结点,f表示黑色,e表示白色。
这里写图片描述
Example Input

3
ppeeefpffeefe
pefepeefe
peeef
peefe
peeef
peepefefe

Example Output

There are 640 black pixels.
There are 512 black pixels.
There are 384 black pixels.

这题放了两天,这两天感冒了一直没想出好的解决办法。。
还是用一个数组表示这棵树,结点里有四个int变量分别表示四个儿子的下标。
初始化数组的时候构造一颗空树(因为注意到合并第二棵树和构造第一棵树的过程类似),根据输入字符串对这棵树计数两次即可。(注释部分用于调试)

#include<bits/stdc++.h>
using namespace std;
//#define ONLINE_JUDGE
#define eps 1e-8
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define INFL 0x3f3f3f3f3f3f3f3fLL
#define enter putchar(10)
#define rep(i,a,b) for(int i = (a); i < (b); ++i)
#define repe(i,a,b) for(int i = (a); i <= (b); ++i)
#define mem(a,b) (memset((a),b,sizeof(a)))
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define sfs(a) scanf("%s",a)
#define pf(a) printf("%d\n",a)
#define pfd(a,b) printf("%d %d\n",a,b)
#define pfP(a) printf("%d %d\n",a.fi,a.se)
#define pfs(a) printf("%s\n",a)
#define pfI(a) printf("%I64d\n",a)
#define ds(a) int a; sf(a)
#define PR(a,b) pair<a,b>
#define fi first
#define se second
#define LL long long
#define DB double
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;}
template<class T> inline T Min(T a, T b) {return a < b ? a : b;}
template<class T> inline T Max(T a, T b) {return a > b ? a : b;}
int n, m;

#define N 3000
const int M = 5;
char str[N];
struct Elmt {
    int pw;
    char ch;
    int cnt;
    int son[4];
    void Init() {
        this->pw = -1;
        this->ch = 'e';
        this->cnt = 0;
        rep(i, 0, 4) this->son[i] = -1;
    }
};
Elmt tree[N];
void Init() {
    m = -1;
    rep(i, 0, N) tree[i].Init();
}

int Counter(int root, int & p, int pw) {    //计数函数、有建树和计数功能
    int cnt = 0;
    if(tree[root].pw == -1) {               //如果root结点一开始不存在(没数据)(只有根结点一开始可能没数据)
        root = ++m;
        tree[root].pw = pw;
    }
    if(str[p] == '\0') return 0;            //到字符串末尾,返回0
    if(str[p] == 'f' || tree[root].ch == 'f') {//原来的树和现在的树有一个黑结点,不管其他的子结点了,合并
        tree[root].ch = 'f';
        tree[root].pw = pw;
        return cnt = 1 << (pw * 2);
    }
    if(str[p] == 'e') return tree[root].cnt;//如果现在的字符串表示的结点为白结点,不用继续建树,直接返回原来树结点的cnt
    tree[root].ch = str[p];
    rep(i, 0, 4) {                          //依次计算四个儿子的cnt
        if(tree[root].son[i] == -1) {
            tree[root].son[i] = ++m;
        }
        int son = tree[root].son[i];
        tree[son].pw = pw - 1;
        cnt += Counter(son, ++p, pw - 1);
    }
    return tree[root].cnt = cnt;            //返回
}




int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
//  freopen("Out.txt", "w", stdout);
#endif
    ds(t);
    while(t--) {
        Init();
        sfs(str);
        int p = 0;
        Counter(0, p, 5);                   //建树 + 统计
//      int cnt1 = Counter(0, p, 5);
        sfs(str);
        p = 0;
//      int cnt2 = Counter(0, p, 5);
//      pfd(cnt1, cnt2);
        printf("There are %d black pixels.\n", Counter(0, p, 5));       //合并 + 统计
    }
    return 0;
}
内含资源如下: 1.基本数据结构 1.1.Array ........... 动态数组 1.2.LinkedList ... 链表 1.3.BST .............. 二分搜索树 1.4.MapBST ..... 二分搜索树(用于实现映射) 1.5.AVLTree ...... AVL树 2.接口 2.1.Queue ........... 队列接口 2.2.Stack .............. 栈接口 2.3.Set .................. 集合接口 2.4.Map ............... 映射接口 2.5.Merger .......... 自定义函数接口 2.6.UnionFind ..... 并查集接口 3.高级数据结构 3.1.ArrayQueue .......................... 队列_基于动态数组实现 3.2.LinkedListQueue .................. 队列__基于链表实现 3.3.LoopQueue ........................... 循环队列_基于动态数组实现 3.4.PriorityQueue ....................... 优先队列_基于最大二叉堆实现 3.5.ArrayPriorityQueue ............. 优先队列_基于动态数组实现 3.6.LinkedListPriorityQueue ..... 优先队列_基于链表实现 3.7.ArrayStack ............................. 栈_基于动态数组实现 3.8.LinkedListStack ..................... 栈_基于链表实现 3.9.BSTSet ..................................... 集合_基于二分搜索树实现 3.10.LinkedListSet ....................... 集合_基于链表实现 3.11.BSTMap ................................ 映射_基于二分搜索树实现 3.12.AVLTreeMap ....................... 映射_ 基于AVL树实现 3.13.LinkedListMap .................... 映射_基于链表实现 3.14.MaxHeap ............................. 最大二叉堆 3.15.SegmentTree ...................... 线段树 3.16.Trie ......................................... 字典树 3.17.QuickFind ............................ 并查集_基于数组实现 3.18.QuickUnion ......................... 并查集_基于树思想实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值