洛谷P1032 字串變換 【kmp,字串hash】
阿新 • • 發佈:2018-12-12
大意
給定轉換規則,求最小步數
思路
其實可以用AC自動機
這道題是問我們最小步數,因為其分支不大()容易想到專門處理最優化問題的演算法
在的匹配中,本人採用的是用字元陣列模擬字串中的運算,建立新的“”,然後在匹配過程中,使用實現,對於判重,使用
程式碼
#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);//輸出
}