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;
}


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