Poj 3294 Life Forms

来源:互联网 发布:淘宝助理5.7使用教程 编辑:程序博客网 时间:2024/05/17 08:25

题目链接:http://poj.org/problem?id=3294

本题练习后缀数组和LCP.二分查找长度是否满足条件即可。

后缀数组模板:

int sa[Maxn],t[Maxn],t2[Maxn],c[Maxn];int rank[Maxn],height[Maxn];//传递的两个参数:n是数组大小,m是数组内元素的Ascii码的最大值+1void build_sa(int n,int m){    int i,*x = t,*y = t2;    //基数排序    for(i=0; i<m; i++) c[i] = 0;    for(i=0; i<n; i++) c[x[i] = s[i]]++;    for(i=1; i<m; i++) c[i] += c[i-1];    for(i = n-1; i>=0; i--) sa[--c[x[i]]] = i;    for(int k=1; k<=n; k<<=1)    {        int p = 0;        //直接利用sa数组排序第二关键字        for(i = n-k; i<n; i++) y[p++] = i;        for(i = 0; i<n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;        //基数排序第一关键字        for(i = 0; i < m; i++) c[i] = 0;        for(i = 0; i < n; i++) c[x[y[i]]]++;        for(i = 0; i < m; i++) c[i] += c[i-1];        for(i = n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];        //根据sa 和y数组计算新的x数组        swap(x,y);        p = 1;        x[sa[0]] = 0;        for(i=1; i<n; i++)        {            x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1] + k] == y[sa[i] + k] ? p-1 : p++;        }        if(p >= n) break;        m = p;    }}//注意getHeight传递入的参数是原数组的长度-1.切记void getHeight(int n){    int i, j, k = 0;    for(i = 1; i <= n; ++i) rank[sa[i]] = i;    for(i = 0; i < n; height[rank[i++]] = k)        for(k? k-- : 0, j = sa[rank[i] - 1]; s[i + k] == s[j + k]; ++k);    return;}
本题要注意两点:getHeight(n)中传递的参数是数组长度-1,然后二分法的时候边界要小心,n=1时,直接输出原字符串即可。

#include <iostream>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <map>#include <queue>#include <algorithm>using namespace std;#define Maxn 250000#define Maxm 155int s[Maxn];int sa[Maxn],t[Maxn],t2[Maxn],c[Maxn];int rank[Maxn],height[Maxn];int tot;//整合后串的长度//原串的个数int n;//整合后的新串中序号为i的字符归属的原串序号int num[Maxn];//当前段中含有的原串的后缀的个数int flag[Maxm];//最终解的后缀的序号(多组解不唯一)int res[Maxn];//最终解的个数int ans_num;void build_sa(int n,int m){    int i,*x = t,*y = t2;    //基数排序    for(i=0; i<m; i++) c[i] = 0;    for(i=0; i<n; i++) c[x[i] = s[i]]++;    for(i=1; i<m; i++) c[i] += c[i-1];    for(i = n-1; i>=0; i--) sa[--c[x[i]]] = i;    for(int k=1; k<=n; k<<=1)    {        int p = 0;        //直接利用sa数组排序第二关键字        for(i = n-k; i<n; i++) y[p++] = i;        for(i = 0; i<n; i++) if(sa[i] >= k) y[p++] = sa[i] - k;        //基数排序第一关键字        for(i = 0; i < m; i++) c[i] = 0;        for(i = 0; i < n; i++) c[x[y[i]]]++;        for(i = 0; i < m; i++) c[i] += c[i-1];        for(i = n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];        //根据sa 和y数组计算新的x数组        swap(x,y);        p = 1;        x[sa[0]] = 0;        for(i=1; i<n; i++)        {            x[sa[i]] = y[sa[i-1]] == y[sa[i]] && y[sa[i-1] + k] == y[sa[i] + k] ? p-1 : p++;        }        if(p >= n) break;        m = p;    }}void getHeight(int n){    int i, j, k = 0;    for(i = 1; i <= n; ++i) rank[sa[i]] = i;    for(i = 0; i < n; height[rank[i++]] = k)        for(k? k-- : 0, j = sa[rank[i] - 1]; s[i + k] == s[j + k]; ++k);    return;}bool possible(int L){    memset(flag,0,sizeof(flag));    int t = 0;//包含原串的个数    int lock = 0;    for(int i=1; i<tot; i++)    {        if(height[i] >= L)        {            flag[num[sa[i]]] = flag[num[sa[i-1]]] = 1;        }        else        {            for(int j=0; j<n; j++) if(flag[j]) t++;            if(t>n/2)            {                if(lock == 0)                {                    ans_num = 0;                    lock = 1;                }                res[ans_num++] = sa[i-1];            }            memset(flag,0,sizeof(flag));            t = 0;        }    }    //处理最后的段    t = 0;    for(int j=0; j<n; j++) if(flag[j]) t++;    if(t>n/2)    {        if(lock == 0)        {            ans_num = 0;            lock = 1;        }        res[ans_num++] = sa[n-1];    }    if(lock == 1) return true;    return false;}void binarySearch(int _l,int _r){    int l = _l,r = _r;    int mid;//最长的长度    int ans_len = l;    int lock = 0;    while(l < r)    {        mid = (l + r + 1)/2;        if(possible(mid))        {            lock = 1;            ans_len = mid;            l = mid;        }        else        {            r = mid - 1;        }    }    if(possible(ans_len)) lock = 1;    if(!lock)    {        puts("?");        return;    }    for(int i=0; i<ans_num; i++)    {        for(int j=res[i]; j<res[i] + ans_len; j++) printf("%c",s[j] - 1 + 'a');        puts("");    }}int main(){#ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);#endif    int len;    int r = 0,l = 0;    char temp[1500];    int cas = 0;    while(scanf(" %d",&n)!=EOF && n!=0)    {        cas++;        if(cas!=1) puts("");        tot = 0;        l = 1;        r = 0;//最长的长度        for(int i=0; i<n; i++)        {            scanf(" %s",temp);            len = strlen(temp);            if(len > r) r = len;            for(int j=0; j<len; j++)            {                num[tot] = i;                s[tot++] = temp[j] - 'a' + 1;            }            s[tot++] = 26 + i + 1;        }        s[tot++] = 0;        if(n == 1)        {            printf("%s\n",temp);            continue;        }        build_sa(tot,26 + n + 1);        //注意传递的参数是长度-1        getHeight(tot-1);        binarySearch(l,r);    }    return 0;}



原创粉丝点击