程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Poj 3294 Life Forms

Poj 3294 Life Forms

編輯:C++入門知識

本題練習後綴數組和LCP.二分查找長度是否滿足條件即可。

後綴數組模板:


[cpp]
int sa[Maxn],t[Maxn],t2[Maxn],c[Maxn]; 
int rank[Maxn],height[Maxn]; 
//傳遞的兩個參數:n是數組大小,m是數組內元素的Ascii碼的最大值+1  
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; 
    } 

//注意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; 

int sa[Maxn],t[Maxn],t2[Maxn],c[Maxn];
int rank[Maxn],height[Maxn];
//傳遞的兩個參數:n是數組大小,m是數組內元素的Ascii碼的最大值+1
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;
    }
}
//注意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時,直接輸出原字符串即可。


[cpp]
#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 155  
int 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; 

#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 155
int 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;
}

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved