Hopcroft DFA 最小化算法
复杂度 \(O(n\log n |\Sigma|)\) 非常优秀。
先存个板子。NOI 之后再讲解。
#include <cstdio>
#include <cassert>
#include <vector>
#include <algorithm>
using namespace std;
int read(){
char c=getchar();int x=0;
while(c<48||c>57) c=getchar();
do x=(x<<1)+(x<<3)+(c^48),c=getchar();
while(c>=48&&c<=57);
return x;
}
const int N=500003;
vector<int> vec[N][10],eq[N],ele[N];
int bel[N],sz[N];
int n,m,cnt;
int que[N],tl;
int stk[N],tp;
bool tag[N],ed[N],ava[N];
int tr[N][10];
bool check(){
for(int i=1;i<=cnt;++i){
int c=0;
for(int t:eq[i]) if(bel[t]==i) ++c;
if(c!=sz[i]) return 0;
}
return 1;
}
int main(){
freopen("hopcroft.in","r",stdin);
freopen("hopcroft.out","w",stdout);
n=read();m=read();int st=read();//点数,边数,起点
cnt=2;
for(int i=1;i<=n;++i) ava[i]=read();//接受节点
for(int i=1;i<=m;++i){
int u=read(),v=read(),c=read();
vec[v][c].emplace_back(u);
}
for(int i=1;i<=n;++i)
if(ava[i]) eq[1].emplace_back(i),bel[i]=1,++sz[1];
else eq[2].emplace_back(i),bel[i]=2,++sz[2];
assert(check());
que[tl=1]=1;ed[1]=1;
for(int pos=1;pos<=tl;++pos){
int x=que[pos];
vector<int> tmp;
for(int p:eq[x])
if(bel[p]==x) tmp.emplace_back(p);
swap(eq[x],tmp);
for(int c=0;c<10;++c){
for(int p:eq[x])
for(int q:vec[p][c]){
if(ele[bel[q]].empty()) stk[++tp]=bel[q];
ele[bel[q]].emplace_back(q);tag[q]=1;
}
while(tp){
int y=stk[tp--];
if(int(ele[y].size())<sz[y]){
ed[++cnt]=ed[y];
if((int(ele[y].size())<<1)<=sz[y]){
for(int p:ele[y]) eq[bel[p]=cnt].emplace_back(p);
sz[cnt]=ele[y].size();
sz[y]-=ele[y].size();
}
else{
vector<int> tmpy;
sz[y]=0;
for(int p:eq[y])
if(bel[p]==y){
if(tag[p]) tmpy.emplace_back(p),++sz[y];
else eq[bel[p]=cnt].emplace_back(p),++sz[cnt];
}
swap(eq[y],tmpy);
}
que[++tl]=cnt;
}
for(int p:ele[y]) tag[p]=0;
ele[y].clear();
assert(check());
}
}
}
printf("%d\n",cnt);//点数
printf("%d\n",bel[st]);//起点
for(int i=1;i<=cnt;++i) printf("%d ",ed[i]);//接受节点
putchar('\n');
for(int i=1;i<=n;++i)
for(int c=0;c<10;++c)
for(int p:vec[i][c]) tr[bel[p]][c]=bel[i];
for(int i=1;i<=cnt;++i){
putchar('{');
for(int c=0;c<10;++c)
printf("%d%c",tr[i][c],",}"[c==9]);
putchar(',');
putchar('\n');
}
return 0;
}