我在B站学算法之第二弹,详细讲解见详细讲解
原题地址
代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll ;
struct node
{
int fail,end;
int ch[30];
}tr[1000010];
int cnt=0,n;
struct result
{
int num,pos;
}ans[160];
bool operator<(result a,result b)
{
if(a.num!=b.num) return a.num>b.num;
else return a.pos<b.pos;
}
string s[160];
queue<int>ww;
inline void clean(int x)
{
memset(tr[x].ch,0,sizeof(tr[x].ch));
tr[x].fail=0;tr[x].end=0;
}
void build(string p,int num)
{
int len=p.length(),s,i,u=0;
for(i=0;i<len;i++)
{
s=p[i]-'a';
if(!tr[u].ch[s])
{
tr[u].ch[s]=++cnt;
clean(cnt);
}
u=tr[u].ch[s];
}
tr[u].end=num;
}
void get_fail()
{
int i,u=0;
for(i=0;i<26;i++)
{
if(tr[u].ch[i])
{
tr[tr[u].ch[i]].fail=0;
ww.push(tr[u].ch[i]);
}
}
while(!ww.empty())//类似BFS,确保较深的结点的fail落在低一级结点上
{
u=ww.front();
ww.pop();
for(i=0;i<26;i++)
{
if(tr[u].ch[i])
{
tr[tr[u].ch[i]].fail=tr[tr[u].fail].ch[i];
ww.push(tr[u].ch[i]);
}
else tr[u].ch[i]=tr[tr[u].fail].ch[i];//虚指针
}
}
}
void AC()
{
int len,u=0,i,v,sl;
len=s[0].length();
for(i=0;i<len;i++)
{
sl=s[0][i]-'a';
u=tr[u].ch[sl];
v=u;
while(v)
{
if(tr[v].end) ans[tr[v].end].num++;
v=tr[v].fail;
}
}
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
int i,j,k;
while(cin>>n&&n)
{
cnt=0;
clean(0);
for(i=1;i<=n;i++)
{
cin>>s[i];
build(s[i],i);
ans[i].num=0;ans[i].pos=i;
}
tr[0].fail=0;
get_fail();
cin>>s[0];
AC();
sort(ans+1,ans+n+1);
cout<<ans[1].num<<endl<<s[ans[1].pos]<<endl;
for(i=2;i<=n;i++)
{
if(ans[i].num==ans[1].num) cout<<s[ans[i].pos]<<endl;
else break;
}
}
return 0;
}
原题地址
代码:
使用拓扑排序对AC自动机进行优化,即对AC过程不再暴力跳fail,详细讲解见该题题解。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll ;
struct node
{
int fail,end,ss;
int ch[30];
}tr[200010];
int cnt=0,n;
int mmp[200020],in[200020],vis[200020];
string s[200020];
queue<int>ww;
queue<int>tp;
void build(string p,int num)
{
int len=p.length(),s,i,u=0;
for(i=0;i<len;i++)
{
s=p[i]-'a';
if(!tr[u].ch[s])
{
tr[u].ch[s]=++cnt;
}
u=tr[u].ch[s];
}
if(!tr[u].end) tr[u].end=num;
mmp[num]=tr[u].end;
}
void get_fail()
{
int i,u=0;
for(i=0;i<26;i++)
{
if(tr[u].ch[i])
{
tr[tr[u].ch[i]].fail=0;
ww.push(tr[u].ch[i]);
}
}
while(!ww.empty())
{
u=ww.front();
ww.pop();
for(i=0;i<26;i++)
{
if(tr[u].ch[i])
{
tr[tr[u].ch[i]].fail=tr[tr[u].fail].ch[i];
in[tr[tr[u].fail].ch[i]]++;
ww.push(tr[u].ch[i]);
}
else tr[u].ch[i]=tr[tr[u].fail].ch[i];
}
}
}
void tpsort()
{
int i,u,p;
for(i=1;i<=cnt;i++)
{
if(!in[i]) tp.push(i);
}
while(!tp.empty())//拓扑排序操作
{
u=tp.front();tp.pop();vis[tr[u].end]=tr[u].ss;
p=tr[u].fail;in[p]--;
tr[p].ss+=tr[u].ss;
if(!in[p]) tp.push(p);
}
}
void AC()
{
int len,u=0,i,v,sl;
len=s[0].length();
for(i=0;i<len;i++)
{
sl=s[0][i]-'a';
u=tr[u].ch[sl];
if(u) tr[u].ss++;
}
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int i,j,k;
cin>>n;
cnt=0;
for(i=1;i<=n;i++)
{
cin>>s[i];
build(s[i],i);
}
tr[0].fail=0;
get_fail();
cin>>s[0];
AC();tpsort();
for(i=1;i<=n;i++)
{
cout<<vis[mmp[i]]<<endl;
}
return 0;
}
原题地址
代码:
代码来源
一开始不会做,但看了讲解就会了。实在懒得敲了(懒癌又犯了)。看了大佬的代码后发现其实AC自动机的fail指针和kmp的next数组有极大的相似之处。
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define pb push_back
#define FOR(a) for(int i=1;i<=a;i++)
const int inf = 0x3f3f3f3f;
const int maxn = 5e5 + 9;
struct pos {
int x, y, z;
}pre[111][111][111], tail;
char a[111], b[111], c[111];
int dp[111][111][111]; //a前i位b前j位匹配到c串k位时的最长长度
int f[111];
void getfail(char *p, int *f)//只有一个匹配串的ac自动机,感觉就是kmp...
{
f[0] = 0; f[1] = 0;
for (int i = 1; p[i]; i++) {
int j = f[i];
while (j&&p[i] != p[j])j = f[j];
f[i + 1] = p[i] == p[j] ? j + 1 : 0;
}
}
void dfs(pos t) {
if (!t.x && !t.y && !t.z)return;
pos q = pre[t.x][t.y][t.z];
int i = q.x, j = q.y, k = q.z;
dfs(q);
if (dp[i][j][k] + 1 == dp[t.x][t.y][t.z])printf("%c", a[i]);
}
int main()
{
cin >> a;
cin >> b;
cin >> c;
getfail(c, f);
memset(dp, 0, sizeof dp);
int len1 = strlen(a), len2 = strlen(b), len3 = strlen(c);
for (int i = 0; i < len1; i++)
{
for (int j = 0; j < len2; j++)
{
for (int k = 0; k < len3; k++)
{
if (dp[i + 1][j][k] < dp[i][j][k])
{
dp[i + 1][j][k] = dp[i][j][k];
pre[i + 1][j][k].x = i;
pre[i + 1][j][k].y = j;
pre[i + 1][j][k].z = k;
}
if (dp[i][j + 1][k] < dp[i][j][k])
{
dp[i][j + 1][k] = dp[i][j][k];
pre[i][j + 1][k].x = i;
pre[i][j + 1][k].y = j;
pre[i][j + 1][k].z = k;
}
if (a[i] == b[j])
{
int w = k;
while (w&&a[i] != c[w])w = f[w];
if (a[i] == c[w])w++;
else w = 0;
if (dp[i + 1][j + 1][w] < dp[i][j][k] + 1)
{
dp[i + 1][j + 1][w] = dp[i][j][k] + 1;
pre[i + 1][j + 1][w].x = i;
pre[i + 1][j + 1][w].y = j;
pre[i + 1][j + 1][w].z = k;
}
}
}
}
}
int maxx = 0;
for (int i = 0; i <= len1; i++)
for (int j = 0; j <= len2; j++)
for (int k = 0; k < len3; k++) {
if (dp[i][j][k] > maxx) {
maxx = dp[i][j][k];
tail.x = i; tail.y = j; tail.z = k;
}
}
if (maxx == 0)return 0 * printf("0\n");
dfs(tail);
}