一些數據結構的實現

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章