1. 程式人生 > >洛谷P1032 字串變換 【kmp,字串hash】

洛谷P1032 字串變換 【kmp,字串hash】

大意

給定轉換規則,求最小步數

思路

其實可以用AC自動機

這道題是問我們最小步數,因為其分支不大(7\leq7)容易想到專門處理最優化問題的bfsbfs演算法

bfsbfs的匹配中,本人採用的是用字元陣列模擬字串中的運算,建立新的“StringString”,然後在匹配過程中,使用KMPKMP實現,對於判重,使用hash+maphash+map

程式碼

#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
using
namespace std;char a[7][21],b[7][21];//轉換規則串 const int base=233;//hash值 int n,ans,kmp[21]; unsigned long long zd;//目標串的hash值 map<unsigned long long,bool>m;//map庫 struct String//定義一種結構體 { char c[101];//字串 int next[101],bs;//kmp_next陣列,bs表示當前步數 inline int size(){return strlen(c);}//長度 inline void
read(){scanf("%s",c);return;}//輸入 inline void build()//建立next陣列 { next[0]=-1; int j=-1; for(register int i=1;i<strlen(c);i++) { while(j>-1&&c[j+1]!=c[i]) j=next[j]; if(c[j+1]==c[i]) j++; next[i]=j; } return
; } inline int find(char s[])//查詢s在c中出現的所有位置,並返回子串個數,複雜度n+m { int j=-1,len=0; for(register int i=0;i<strlen(c);i++) { while(j>-1&&s[j+1]!=c[i]) j=next[j]; if(s[j+1]==c[i]) j++; if(j==strlen(s)-1) kmp[++len]=i-j,j=0; } return len; } inline unsigned long long hash()//自然溢位求hash值 { unsigned long long ans=0; for(register int i=0;i<strlen(c);i++)ans=ans*base+c[i]; return ans; } }Begin,End;//定義起始串和目標串 inline int bfs() { queue<String>q;//建立元素為結構體的佇列,方便轉移 q.push(Begin);//放入 while(q.size()) { String x=q.front();x.build();q.pop();//取出並求出next陣列 if(x.bs==10) continue;//超出步數不管它 for(register int i=0;i<n;i++) { int len=x.find(a[i]),lena=strlen(a[i]),lenb=strlen(b[i]); if(!len) continue;//沒有匹配串退出 for(register int cs=1;cs<=len;cs++) { String y=x; y.bs=x.bs+1;//bs多了一步 int t=kmp[cs];//取出位置 if(lena==lenb)for(register int j=t;j<t+lena;j++) y.c[j]=b[i][j-t];//長度相同直接賦值 if(lena<lenb)//長度將變長 { for(register int k=1;k<=lenb-lena;k++) for(register int j=y.size()+(lenb-lena)-1;j>=t+lena;j--) y.c[j]=y.c[j-(lenb-lena)];//將後面的往前挪長度差次 for(register int j=t;j<t+lenb;j++) y.c[j]=b[i][j-t];//轉換 } if(lena>lenb)//長度將變短 { for(register int j=t;j<t+lenb;j++) y.c[j]=b[i][j-t];//轉換 for(register int k=1;k<=lena-lenb;k++) for(register int j=t+lenb;j<y.size();j++) y.c[j]=y.c[j+1];//將前面的往後挪長度差位 } unsigned long long hh=y.hash();//計算hash值 if(hh==zd) return y.bs;//到達終點,返回步數 if(m.find(hh)==m.end()) q.push(y),m[hh]=true;//若沒有出現過,將其入隊 } } } return -1; } signed main() { Begin.read();End.read();zd=End.hash();//輸入 while(scanf("%s %s",a[n],b[n])!=EOF)n++;//輸入 ans=bfs();//bfs if(ans<0) printf("NO ANSWER!"); else printf("%d",ans);//輸出 }