POJ 数据结构(3)

数据结构

trie图的建立和应用,DFA

hdd2222,poj1204 poj2778, poj3691

LCARMQ问题

poj1330

双端队列和它的应用

poj2823(单调队列)

左偏树

poj3666poj3016

后缀树,后缀数组

poj3415,poj3294, poj2774

poj2758

 

 

 

 

 

 

 

 

 

 

  

 

 

 

trie图的建立和应用,DFA 

hdu2222

很裸的题,可以作为模板:

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <map>
#include <sstream>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   x < y ? x : y
#define Max(x, y)   x < y ? y : x
#define E(x)    (1 << (x))

const int eps = 1e-6;
const int inf = ~0u>>2;
typedef long long LL;

using namespace std;

class Node {
public:
    Node* fail;
    Node* next[26];
    int cnt;
    Node() {
        CL(next, 0);
        fail = NULL;
        cnt = 0;
    }
};

//Node* q[10000000];

class AC_automaton : public Node{
public:
    Node *root;
    int head, tail;

    void init() {
        root = new Node();
        head = tail = 0;
    }

    void insert(char* st) {
        Node* p = root;
        while(*st) {
            if(p->next[*st-'a'] == NULL) {
                p->next[*st-'a'] = new Node();
            }
            p = p->next[*st-'a'];
            st++;
        }
        p->cnt++;
    }

    void build() {
        root->fail = NULL;
        deque<Node* > q;
        q.push_back(root);

        while(!q.empty()) {
            Node* tmp = q.front();
            Node* p = NULL;
            q.pop_front();
            for(int i = 0; i < 26; ++i) {
                if(tmp->next[i] != NULL) {
                    if(tmp == root) tmp->next[i]->fail = root;
                    else {
                        p = tmp->fail;
                        while(p != NULL) {
                            if(p->next[i] != NULL) {
                                tmp->next[i]->fail = p->next[i];
                                break;
                            }
                            p = p->fail;
                        }
                        if(p == NULL)   tmp->next[i]->fail = root;
                    }
                    q.push_back(tmp->next[i]);
                }
            }
        }
    }

    int search(char* st) {
        int cnt = 0, t;
        Node* p = root;
        while(*st) {
            t = *st - 'a';
            while(p->next[t] == NULL && p != root) {
                p = p->fail;
            }
            p = p->next[t];
            if(p == NULL)   p = root;

            Node* tmp = p;
            while(tmp != root && tmp->cnt != -1) {
                cnt += tmp->cnt;
                tmp->cnt = -1;
                tmp = tmp->fail;
            }
            st++;
        }
        return cnt;
    }
}AC;

char dic[100], st[1000010];

int main() {
    freopen("data.in", "r", stdin);

    int t, n, ans;
    scanf("%d", &t);

    while(t--) {
        scanf("%d", &n);
        AC.init();
        while(n--) {
            scanf("%s", dic);
            AC.insert(dic);
        }
        AC.build();
        scanf("%s", st);
        ans = AC.search(st);
        cout << ans << endl;
    }
    return 0;
}

 

 

poj 1204

题意是给一个字符串矩阵。然后给一些模式串,问这个模式串在矩阵的哪个位置被找到(可以从矩阵中的某个点向八个方向扩展)。。。输出开始坐标和方向。

解:用trie图写的,看得gw老师的课件。。。对模式串反向建trie图就可以,好蛋疼的是模式串为

ABC

ABCDEF

这种形式。。。需要加一个vector记录危险节点为A的所有串的编号。。。

从早晨一直搞。。。终于搞过了,拍了近4.5k的代码。。。

详见代码:

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <map>
#include <sstream>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   x < y ? x : y
#define Max(x, y)   x < y ? y : x
#define E(x)    (1 << (x))

const int eps = 1e-6;
const int inf = ~0u>>2;
typedef long long LL;

using namespace std;

const int N = 1024;
const int LET = 26;
int nNodesCount = 0;

struct CNode {
    CNode * ch[LET];
    CNode * pPre;
    vector<int> bstopNode;
    int num;
    CNode() {
        CL(ch, 0);
        bstopNode.clear();
        pPre = NULL;
    }
};

CNode T[100000];
char mp[N][N];
int r, c, m;
bool vis[N] = {false};


int dir[8][2] = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}};

void insert(CNode* p, char* s, int x) {
    int i, l = strlen(s);
    for(i = l - 1; i >= 0; --i) {
        if(p->ch[s[i]-'A'] == NULL) {
            p->ch[s[i]-'A'] = T + nNodesCount++;
        }
        p = p->ch[s[i] - 'A'];
    }
    p->bstopNode.push_back(x);
}

void buildDFA() {
    int i;
    for(i = 0; i < LET; ++i) {
        T[0].ch[i] = T + 1;
    }
    T[0].pPre = NULL;
    T[1].pPre = T;

    deque<CNode *> q;
    q.push_back(T + 1);

    while(!q.empty()) {
        CNode * proot = q.front();
        q.pop_front();
        for(i = 0; i < LET; ++i) {
            CNode* p = proot->ch[i];

            if(p) {
                CNode* father = proot->pPre;
                while(father) {
                    if(father->ch[i]) {
                        p->pPre = father->ch[i];

                        if(p->pPre->bstopNode.size() != 0) {
                            vector<int>::iterator it;
                            for(it = p->pPre->bstopNode.begin(); it != p->pPre->bstopNode.end(); ++it)
                                p->bstopNode.push_back(*it);
                        }

                        break;
                    } else
                        father = father->pPre;
                }
                q.push_back(p);
            }
        }
    }
}

bool inmap(int x, int y) {
    if(x < 0 || x >= r || y < 0 || y >= c)  return false;
    return true;
}

struct node {
    int x, y;
    char c;
    node() {}
    node(int a, int b, char d) : x(a), y(b), c(d) {}
} ans[10000];

bool search(int sx, int sy, int d) {
    CNode* p = T + 1;
    int x, y;
    for(x = sx, y = sy; inmap(x, y); x += dir[d][0], y += dir[d][1]) {
        while(true) {
            if(p->ch[mp[x][y] - 'A']) {
                p = p->ch[mp[x][y] - 'A'];
                if(p->bstopNode.size() != 0) {
                    //printf("%d %d %d\n", x, y, p->num);
                    vector<int>::iterator it;
                    for(it = p->bstopNode.begin(); it != p->bstopNode.end(); ++it)
                        if(!vis[*it]) {
                            ans[*it] = node(x, y, (d + 4)%8 + 'A');
                            vis[*it] = true;
                        }
                    //return true;
                }
                break;
            } else  p = p->pPre;
        }
    }
    return false;
}

void solve() {
    buildDFA();
    int i;
    for(i = 0; i < r; ++i) {
        search(i, 0, 2);
        search(i, 0, 1);
        search(i, 0, 3);
        search(i, c - 1, 6);
        search(i, c - 1, 5);
        search(i, c - 1, 7);
    }
    for(i = 0; i < c; ++i) {
        search(0, i, 4);
        search(0, i, 5);
        search(0, i, 3);
        search(r - 1, i, 0);
        search(r - 1, i, 1);
        search(r - 1, i, 7);
    }
}

int main() {
    //freopen("data.in", "r", stdin);

    int i;
    scanf("%d%d%d", &r, &c, &m);
    for(i = 0; i < r; ++i) {
        scanf("%s", mp[i]);
    }
    char st[N];
    nNodesCount = 2;
    for(i = 0; i < m; ++i) {
        scanf("%s", st);
        insert(T + 1, st, i);
    }
    solve();
    for(i = 0; i < m; ++i) {
        printf("%d %d %c\n", ans[i].x, ans[i].y, ans[i].c);
    }
    return 0;
}

 

 poj 2278&&3691

http://www.cnblogs.com/vongang/archive/2012/11/06/2756422.html

 

 

 

LCARMQ问题 

poj 1330

题意很裸,就是求LCA。

LCA转化为RMQ的方法:http://www.cnblogs.com/vongang/archive/2012/05/03/2481196.html

RMQ写搓了。。。wa了3次。。。

谨记!

View Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <map>
#include <sstream>

#define CL(arr, val)    memset(arr, val, sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   x < y ? x : y
#define Max(x, y)   x < y ? y : x
#define E(x)    (1 << (x))

const int eps = 1e-6;
const int inf = ~0u>>2;
typedef long long LL;

using namespace std;

const int N = 20010;


int D[N], E[N], R[N];

class RMQ {
public:
    int Min[N][20];
    void build(int n) {
        int i, j, m;
        for(i = 1; i <= n; ++i) Min[i][0] = i;
        m = int(log(double(n))/log(2.0));
        FOR(j, 1, m) {
            FOR(i, 1, n - (1<<j) + 1) {
                if(D[Min[i][j-1]] < D[Min[i+(1<<(j-1))][j-1]]) {
                    Min[i][j] = Min[i][j-1];
                } else {
                    Min[i][j] = Min[i+(1<<(j-1))][j-1];
                }

            }
        }
    }

    int query(int s, int e) {
        int k = log(double(e - s + 1))/log(2.0);
        if(D[Min[s][k]] < D[Min[e-(1<<k) + 1][k]])   return  Min[s][k];
        else    return Min[e-(1<<k) + 1][k];
    }
} Q;

vector<int> g[N];

int in[N], cnt;
bool vis[N];

void init(int n) {
    CL(in, 0); CL(D, 0);
    CL(E, 0); CL(R, 0);
    CL(vis, 0); cnt = 1;
    for(int i = 1; i <= n; ++i) {
        g[i].clear();
    }
}

void dfs(int t, int dep) {
    if(!vis[t]) {
        R[t] = cnt;
        vis[t] = true;
    }

    D[cnt] = dep;
    E[cnt++] = t;
    for(int i = 0; i < int(g[t].size()); ++i) {
        dfs(g[t][i], dep + 1);
        D[cnt] = dep;
        E[cnt++] = t;
    }
}

int main() {
    //freopen("data.in", "r", stdin);

    int t, i, n, x, y;
    scanf("%d", &t);
    while(t--) {

        scanf("%d", &n);
        init(n);
        REP(i, n - 1) {
            scanf("%d%d", &x, &y);
            g[x].push_back(y);
            in[y]++;
        }
        FOR(i, 1, n) {
            if(in[i] == 0)  {
                dfs(i, 0);
                break;
            }
        }
        cnt--;
        Q.build(cnt);

        scanf("%d%d", &x, &y);
        x = R[x], y = R[y];
        if(x > y)   swap(x, y);
        printf("%d\n", E[Q.query(x, y)]);
    }
    return 0;
}

 

双端队列和它的应用 

poj 2823 (单调队列)

单调队列的原理是双端队列,好吧,我只能说这个标题没有错。。。

单调队列的思想是保证窗口的元素的value是从前往后是依次减小(增大)的。还有一个值就是当前value的position,也就是说窗口里所有元素的position都必须跟当前待插入的元素的position的距离相差小于等于窗口的大小。(-_-! 说的好别扭)

View Code
// 单调队列模板

const int N = 1000010;

class Node {
public:
    int pos;
    int num;
    Node() {};
    Node(int _a, int _b) : pos(_a), num(_b) {}
};

class Dequ{
    Node deq[N];
public:
    void Get_Min(int ans[], int _num[], int n, int k) {
        int i, head, tail;
        head = tail = 0;
        REP(i, n) {
            if(head < tail && deq[head].pos <= i - k)   head++;
            while(head < tail && deq[tail-1].num >= _num[i])    tail--;

            deq[tail++] = Node(i, _num[i]);
            ans[i] = deq[head].num;
        }
    }
    void Get_Max(int ans[], int _num[], int n, int k) {
        int i, head, tail;
        head = tail = 0;
        REP(i, n) {
            if(head < tail && deq[head].pos <= i - k)   head++;
            while(head < tail && deq[tail-1].num <= _num[i])    tail--;

            deq[tail++] = Node(i, _num[i]);
            ans[i] = deq[head].num;
        }
    }
} Dequeue;

 

 

左偏树 

poj 3666

只知道dp的解法。。。左偏树维护中位数真心没看懂。。

先对序列排下序,用排好序的下标代表那个数(算是离散化吧)。

dp[i[[j] 到第i个位置,高度为[1...j]中任意一个的最小花费。

dp[i][j] = dp[i-1][j] + iabs(A[j] - A[i])
if(j > 0)  dp[i][j] = min(dp[i][j-1], dp[i][j];

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2012-07-19 09:21  AC_Von  阅读(1140)  评论(0编辑  收藏  举报