(fzu) Problem D Game(KMP算法,字符串匹配问题)

Accept: 145 Submit: 844
Time Limit: 1000 mSec Memory Limit : 262144 KB
Problem Description
Alice and Bob is playing a game.
Each of them has a number. Alice’s number is A, and Bob’s number is B.
Each turn, one player can do one of the following actions on his own number:
1. Flip: Flip the number. Suppose X = 123456 and after flip, X = 654321
2. Divide. X = X/10. Attention all the numbers are integer. For example X=123456 , after this action X become 12345(but not 12345.6). 0/0=0.
Alice and Bob moves in turn, Alice moves first. Alice can only modify A, Bob can only modify B. If A=B after any player’s action, then Alice win. Otherwise the game keep going on!
Alice wants to win the game, but Bob will try his best to stop Alice.
Suppose Alice and Bob are clever enough, now Alice wants to know whether she can win the game in limited step or the game will never end.
Input
First line contains an integer T (1 ≤ T ≤ 10), represents there are T test cases.
For each test case: Two number A and B. 0<=A,B<=10^100000.
Output
For each test case, if Alice can win the game, output “Alice”. Otherwise output “Bob”.
Sample Input
4
11111 1
1 11111
12345 54321
123 123
Sample Output
Alice
Bob
Alice
Alice
Hint
For the third sample, Alice flip his number and win the game.
For the last sample, A=B, so Alice win the game immediately even nobody take a move.

题意:给定两个整数两个整数A,B(1<=A<=B<=10^100000)
Alice只修改A,Bob只修改B,两人轮流按照以下两种规则操作:
1.反转 2.除10 另外0/0=0!!! 这个坑了我一个小时
假设两个人都想赢,若从Alice先开始修改,轮流选其中一种操作,若能使A=B,那么Alice赢,输出Alice,否则游戏一直进行,不能使A=B,输出Bob

分析:当时做这个训练赛时,比较浮躁,因为当时服务器出现问题,看不了题,群里的一位学长发出了这个题的截图,开始看题,理解题意,A,B两个数的范围太大,因此不可能直接输入,转换成字符串输入,而这个题肯定不是模拟,模拟时间会超限,不超限那数据肯定水了,然后让我一下想到KMP算法的是:这里的第一个和第二个样例,两个样例是反过来的,而输出是不同的,那么再结合题意,知道了只要A的长度比B的小就一定输出Bob,当A的长度不大于B的长度时,就用KMP判断B是不是A的子串,若是,就输出Alice;不是,这里要注意,如果B只有一位且等于0,那么Alice肯定赢,这个条件不满足,就输出Bob了。。。
没注意到题目中的0/0=0,这里就成了这个题比较大的坑…

代码如下:

#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<set>
#include<vector>
#include<iostream>
using namespace std;
const int N=100001;
string a,b;
int la,lb,flag=0;
int ne[N+1];
char c[N+1];
void Ne(int len,int *ne)
{
    ne[0]=-1;
    int i=-1,j=0;
    while(j<len)
    {
        if(i==-1||b[i]==b[j])
        {
            i++;
            j++;
            if(b[i]!=b[j])
                ne[j]=i;
            else
                ne[j]=ne[i];
        }
        else
            i=ne[i];
    }
}
void KMP()
{
    int len1=la,len2=lb;
    Ne(len2,ne);
    int i=0,j=0;
    flag=0;
    //printf("%s\n",c);
    while(i<len1)
    {
        if(j==-1||a[i]==b[j])
        {
            i++;
            j++;
        }
        else
            j=ne[j];
        if(j==len2)
        {
            flag=1;
            return ;
            j=ne[j];
        }
    }
}
void KMP2()
{
    int len1=la,len2=lb;
    Ne(len2,ne);
    int i=0,j=0;
    flag=0;
    //printf("%s\n",c);
    while(i<len1)
    {
        if(j==-1||a[i]==c[j])
        {
            i++;
            j++;
        }
        else
            j=ne[j];
        if(j==len2)
        {
            flag=1;
            return ;
            j=ne[j];
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        //getchar();
        //scanf("%s%s",a,b);
        cin>>a>>b;
        la=a.size(),lb=b.size();
        if(la<lb) puts("Bob");
        else
        {
            KMP();
            if(flag)
                puts("Alice");
            else
            {
                int i,j;
                for(i=lb-1,j=0; i>=0; i--,j++)
                {
                    c[j]=b[i];
                }
                //c[j]='\0';
                //b.reverse();
                //cout<<c<<endl;
                KMP2();
                if(flag)
                    puts("Alice");
                else
                {
                    if(lb==1&&b[0]=='0')///若为0!!!
                    puts("Alice");
                    else puts("Bob");
                }
            }
        }
    }
    return 0;
}

因为对KMP的不熟悉,我写了半天,开的ne数组太大放在了函数内部,RE了,开始ne数组命名是next,然后CE了,这里好像之前碰到过,next重定义了吧?《(fzu) Problem D Game(KMP算法,字符串匹配问题)》
最后没注意到0/0=0,B可能为0,以为自己思路完美了,却WA了一发。。 用了将近40分钟反复看题才才明白,提交注释忘了,又WA了。。。《(fzu) Problem D Game(KMP算法,字符串匹配问题)》

从上面截图来看,KMP算法的高效性可想而知。。

写这么多,只是要记得不要急,仔细审题。。 每一步找出依据。。这样就不会白白WA了
KMP算法的练习还有待加强,说了这么多废话,还是得多看多做

不对的望能指点,谢谢!

顺便贴上学长写的:
字符串匹配的算法我采用的是<<挑战程序设计竞赛>>上的P373
4.7.2字符串匹配中哈希算法用于字符串匹配的Rabin-Karp算法
比KMP更加简洁,复杂度也相差无几。但是严格意义上来说正确
性没那么高

#include <iostream>
#include <cstdio>
#include <string>

using namespace std;

typedef unsigned long long ull;
ull B = 100000007;
//b是否包含a,或者说a有没有在b中出现过
bool contain(string a,string b)
{
    int al=a.length(),bl=b.length();
    if(al>bl) return false;

    ull t=1;
    for(int i=0;i<al;i++) t*=B;

    ull ah=0,bh=0;
    for(int i=0;i<al;i++) ah = ah*B+a[i];
    for(int i=0;i<al;i++) bh = bh*B+b[i];

    for(int i=0;i+al<=bl;i++)
    {
        if(ah==bh)  return true;
        if(i+al<bl) bh = bh*B+b[i+al]-b[i]*t;
    }
    return false;
}
bool allZero(string &an)
{
    for(int i=0;an[i]!='\0';i++)
        if(an[i]!='0')
            return false;
    return true;
}
int main(int argc,char *argv[])
{   //小技巧:解除IOS输入输出流和STDIO的同步
    //可以加快cin读入的速度
    std::ios::sync_with_stdio(false);
    int T;
    scanf("%d",&T);
    string a,b;
    while(T--)
    {
        cin>>a>>b;
        //如果b在a中出现过,或者b字符串都是0
        if(contain(b,a)||allZero(b))
            printf("Alice\n");
        else
        {
            reverse(a.begin(),a.end());//翻转字符串
            if(contain(b,a))
                printf("Alice\n");
            else
                printf("Bob\n");
        }
    }
    return 0;
}
    原文作者:KMP算法
    原文地址: https://blog.csdn.net/feng_zhiyu/article/details/75805076
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞