ACM練習之《自然的謎語》

然後說說我刷題之路遇到的第二題吧:《PID328/自然地謎語》。

5月13號中午,複習了string類後,用str.compare()函數很快搞定了這道題,哈哈,不過提交後只得了80分,顯示TLE,百度:超出時間限制。看了一下最後兩個測評超時了。。完全沒接觸過超時啊,這可怎麼改。看了一下評論,貌似必須用一個KMP算法。。。艹,學!看不懂有木有。。。於是Google了好幾個版本的教程,下到手機上,不斷地看不斷地研究……(順便認識了一個BF算法,複習了指針一堆東西,引用等等。。好吧,我承認我TM快把去年學的東西忘光了。。。)


KMP學習文章一:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

KMP學習文章二:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html

KMP學習文章三:http://www.cnblogs.com/yjiyjige/p/3263858.html


附上BF與KMP練習代碼:

#include <iostream>
#include <cstring>

using namespace std;

int KMPMatch(char *s,char *p);
int BFMatch(char *s, char *p);
void getNext(char *p,int *next);

int main()
{
    char s1[11] = {'a','b','a','b','c','a','b','a','b','a'};
    char s2[6] = {'a','b','a','b','c'};
    cout << BFMatch(s1 , s2) << endl;
    cout << KMPMatch(s1 , s2) << endl;
    return 0;
}

//BF算法
int BFMatch(char *s , char *p)
{
    int i,j;
    i=0;
    while(i<strlen(s))
    {
        j=0;
        while(s[i]==p[j]&&j<strlen(p))
        {
            i++;
            j++;
        }

        if(j==strlen(p))
            return i-strlen(p);
        i = i - j + 1 ;             //指針i回溯
    }
    return -1;
}

//KMP算法
int KMPMatch(char *s,char *p)
{
    int next[100];
    int i,j;
    i=0;
    j=0;
    getNext(p,next);
    while(i<strlen(s))
    {
        if(j==-1||s[i]==p[j])
        {
            i++;
            j++;
        }
        else
        {
            j=next[j];       //消除了指針i的回溯
        }
        if(j==strlen(p))
            return i-j;
    }
    return -1;
}

void getNext(char *p,int *next)
{
    int j,k;
    next[0]=-1;
    j=0;
    k=-1;
    while(j<strlen(p)-1)
    {
        if(k==-1||p[j]==p[k])    //匹配的情況下,p[j]==p[k]
        {
            j++;
            k++;
            next[j]=k;
        }
        else                   //p[j]!=p[k]
            k=next[k];
    }
}



    5月14號,帶着稍稍能看懂那麼一點的KMP算法,重寫了這一題,提交檢測成果……靠,服務器壞了 - -。哭哭哭



2014年5月16日23:46:25更新:

NND,服務器終於好了,TM一看竟然WA30,大失所望。排查出錯誤後再提交,最後三個測試點超時 - -。再改。又錯。再改。又超時……

無奈了,問隊友曹大神,果然他也WA了幾次,哈哈。不過還是被他分分鐘AC了 - -。看他的代碼,感覺和我的差不多啊。。。鬱悶。改來改去無效。放下不管了。。。

晚上,決定刪了自己的代碼仿着曹大神的重寫,可是,竟然又有兩道超時抓狂。。。我可抄的就剩輸入輸出不一樣了。。。換成他的輸出函數,果然AC了。。。然後曹大神告訴我,cin和cout超級慢……(有時可在主函數使用 ios::sync_with_stdio(false);能加快速度)。

額額額,好吧,又漲姿勢了:scanf + printf  要比 cin + cout 運行快。

唉,不管怎麼說,今天終於算是把這道題解決了。看得出來我欠的知識實在太多,需要努力啊。


附上曹大神解此題的源代碼:(很多地方值得我去學習奮鬥

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 100010,MAXM = 100010;
char T[MAXN],P[MAXM];
int Next[MAXM],N,M,C;
int Ans[MAXN];
void MakeNext(int M)
{
    int i=0,j=-1;
    Next[i] = -1;
    while(i<M)
	{
        if(j==-1||P[i]==P[j])Next[++i] = ++j;
        else j = Next[j];
    }
}
int KMP(int pos,int N,int M)
{
    int i = pos, j = 0,ans = 0;
    while(i<N){
        if(T[i]==P[j]||j==-1)i++,j++;
        else j = Next[j];
        if(j==M){
            Ans[++ans]=i-j+1;
            j = Next[j-1];
            i--;
        }
    }
    return ans;
}
int main()
{
    scanf("%s%s",P,T);
    N = strlen(T),M = strlen(P);
    MakeNext(M);
    int ans=KMP(0,N,M);
    if(ans==0)
    {
    	puts("There must be something wrong.");
    	return 0;
    }
    printf("%d\n",ans);
    for(int i=1;i<=ans;i++)
       	printf("%d\n",Ans[i]);
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章