1. 程式人生 > 遊戲攻略 >《原神攻略》2.0版本霧切之回光武器分析

《原神攻略》2.0版本霧切之回光武器分析

前言:

到底什麼是kmp呢?本人認為kmp的優勢在於根據之前的資訊來快速更新現在的資訊,從而提高時間的效率(類似於記憶化搜尋?)在此預設大家都會kmp。

主要用處:

一.字串匹配

程式碼:

#include<bits/stdc++.h>

#define maxn 1000001

using namespace std;

int kmp[maxn];

char a[maxn],b[maxn];

int la,lb;

int j;

int main()

{

    cin>>a+1>>b+1;

    la=strlen(a+1);

    lb=strlen(b+1);

    j=0;

    kmp[1]=0;

    for(int i=2;i<=lb;i++)

    {

     while(j && b[j+1]!=b[i]) j=kmp[j];

     if(b[j+1]==b[i]) j++;

     kmp[i]=j;

}

j=0;

for(int i=1;i<=la;i++)

{

while(j && b[j+1]!=a[i]) j=kmp[j];

if(b[j+1]==a[i]) j++;

if(j==lb)

{

cout<<i-lb+1<<endl;

j=kmp[j];

}

}

for(int i=1;i<=lb;i++) cout<<kmp[i]<<' ';

    return 0;

}

  

重點kmp[i]陣列求的即為i位置匹配失敗時往前跳的花費最小位置,即模式串i位置前與第一位後的最長公共子串。

例:abaabaa

如果此時匹配失敗位置6,則此時直接將指標指向3號,因為1-2=4-5號,所以既然已經匹配到了第6號說明此時匹配串匹配失敗的位置前2=模式串4-5=模式串1-2號,所以下次重新匹配直接從3號開始,不必再從1號開始,大大節約了時間,此為此演算法之精髓。

時間複雜度:O(N)

二.4391(luogu)最小迴圈子串

給你一個字串s1​,它是由某個字串s2​不斷自我連線形成的。但是字串s2​是不確定的,現在只想知道它的最短長度是多少。

Eg:cabcabca

Ans:cab

題解:答案即為l-kmp[l=s.size()];

證明:

(圖在原稿中,無法上傳,此處略去,如果需要可私信作者)

綠色為ans,將字串等量分段,由kmp陣列的特性得知則黃色1=綠色2=黃色2=紅色1=紅色2=藍色1=藍色2=草綠色1(數字為排數),則此時只用證明綠色前一半部分包含灰色,灰色2=草綠色前一部分=綠色前一部分,則得證。

三:2375(luogu)

給一個字串,求每一個位置的公共前後綴且滿足前後綴不交叉的數量。

題解:

先求出num1陣列表示每個位置交叉的前後綴數量,num1即為一直跳nxt直至nxt=0時的次數(注意前後綴既不能少前面也不能少後面,和迴文串不要搞混了,一個公共前後綴不包含別的前後綴,具有唯一性),即可在求

Kmp時遞推求之。接著每一個位置i的ans即為滿足j=while(nxt[i]),(j<<1)<=i的num[j]

這個題對kmp陣列的意義考察的較好,做完這個題,應該會對kmp有更高的認識。

總結

kmp演算法主要用於字串單匹配,前後綴處理一些場景中,時間複雜度也相對可觀,程式碼量較小,但遇到多匹配時,只能上AC自動機了,這可能有樹狀陣列和線段樹的意味