【哈希】poj3576 Language Recognition

求dfa最小化状态

想fhq的小强的颜色都还没做出来

一颗tire是一个满足要求的dfa,但是并不是最小化,我们需要在trie的基础上修改,是他保持原来性质,但是状态量更小

如果两个状态的子树同构的话而且同为或同不为结束状态,那么这两个状态是可以合并的,对于子树可以用以前集训队论文中介绍过的hash来做

考虑两个状态的结合会不会影响其他状态,显然子状态是没有影响的,因为子树是否合并是看子树本身性质而不是祖先性质,而对于祖先来说,子树合并后,自己的子树依旧是相同的,否则就不满足与原trie同构的性质,所以一遍预处理出hash值后以后可以沿用。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int lucknum = 1995309;
using namespace std;
long long c[500000],hash[500000],d[500000];
char ch[1000];
int n,next[200000][27],ans,ss,s1,st[200000],b[200000],u[1000000];
bool final[1000000];
void ins(char ch[1000])
{
    int len,s,x,i;
    len=strlen(ch+1);
    for (s=0,i=1;i<=len;i++) {
	x=ch[i]-'a';
	if (!next[s][x]) next[s][x]=++ss;
	s=next[s][x];
    }
    final[s]=1;
}
bool cmp(int i,int j)
{
    if (d[i]!=d[j]) return d[i]<d[j];
    if (hash[i]!=hash[j]) return hash[i]<hash[j];
    return final[i]<final[j];
}
void bfs(int s)
{
    int h,r,i,ne,na,j;
    h=r=0;
    st[++r]=s,d[s]=0;
    for (;h<r;) {
	ne=st[++h];
	for (i='a'-'a';i<='z'-'a';i++)
	    if (next[ne][i]) {
		na=next[ne][i];
		d[na]=d[ne]+1;
		st[++r]=na;
	    }
    }
    for (i=r;i>=2;i--) {
	ne=st[i],d[ne]=1;
	hash[ne]=1;
	for (j='a'-'a';j<='z'-'a';j++) {
	    na=next[ne][j];
	    if (!na) continue;
	    hash[ne]+=(hash[na]+(final[na] ? lucknum : 0))*c[j];
	    if (d[na]+1>d[ne]) d[ne]=d[na]+1;
	}
    }
    for (i=0;i<=ss;i++) u[i]=i;
    sort(u,u+ss+1,cmp);
    for (i=0;i<=ss;i++)
	if (d[u[i]]==d[u[i-1]] && final[u[i]]==final[u[i-1]] && hash[u[i]]==hash[u[i-1]]) b[u[i]]=u[i-1];
}
void init()
{
    int i;
    scanf("%d\n",&n);
    ss=0;
    for (i=1;i<=n;i++) {
	scanf("%s\n",ch+1);
	ins(ch);
    }
    for (i=0;i<=ss;i++) b[i]=i;
    for (c[0]=1,i=1;i<='z';i++) c[i]=(c[i-1]*13);
    bfs(0);
    ans=0;
    for (i=0;i<=ss;i++) ans+=(b[i]==i);
    printf("%d\n",ans);
}
int main()
{
    init();
    return 0;
}


你可能感兴趣的:(【哈希】poj3576 Language Recognition)