本题是绝对实力不够只能放着的一道题了,AC自动机以及最小树形图已经求出,但是如何输出却迟迟无法想到。
唉。。果然太弱,显放着,等以后有空了再思考一下吧= =||
代码如下:
#include <iostream>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <bitset>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <math.h>
#define maxn 50
#define eps 1e-10
#define mod 1000000009
#define INF 0x3f3f3f3f
#define lowbit(x) (x&(-x))
//#define lson o<<1, L, mid
//#define rson o<<1 | 1, mid+1, R
typedef long long LL;
//typedef int LL;
using namespace std;
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define REPF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REPV( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define clear( a , x ) memset ( a , x , sizeof a )
const int MAXW = 26 ;
const int MAXN = 505 ;
const int MAXQ = 1000000 ;
const int MAXE = 1000000 ;
struct Line {
int u , v , c , f , word ;
int now , pre ;
} ;
struct Edge {
int v , word , f , n ;
} ;
struct Trie {
int end[MAXN] ;
int next[MAXN][MAXW] ;
int fail[MAXN] ;
int Q[MAXQ] , head , tail ;
int P , root ;
int n ;
char buf[MAXN] ;
int word[MAXN] ;
int NV , NE ;
//----------------------------
Line E[MAXE] ;
Edge edge[MAXE] ;
int H[MAXN] , cntE ;
int In[MAXN] ;
int pre[MAXN] ;
int vis[MAXN] ;
int idx[MAXN] ;
int ans[MAXN] ;
int num[MAXN] ;
bool mark[MAXN][MAXN] ;
int p[MAXN] ;
int cnt ;
int newnode ( int x ) {
REP ( i , MAXW )
next[P][i] = -1 ;
end[P] = P ;
word[P] = x ;
return P ++ ;
}
void init () {
NE = 0 ;
P = 0 ;
cnt = 0 ;
cntE = 0 ;
clear ( H , -1 ) ;
clear ( num , 0 ) ;
clear ( mark , 0 ) ;
root = newnode ( -'a' + 'O' ) ;
}
int get ( char &a ) {
return a - 'a' ;
}
void insert ( char buf[] ) {
int now = root ;
for ( int i = 0 ; buf[i] ; ++ i ) {
int x = get ( buf[i] ) ;
if ( next[now][x] == -1 )
next[now][x] = newnode ( x ) ;
now = next[now][x] ;
}
}
void addedge ( int u , int v , int c , int word ) {
E[NE].u = E[NE].pre = u ;
E[NE].v = E[NE].now = v ;
E[NE].c = E[NE].f = c ;
E[NE].word = word ;
NE ++ ;
}
void build () {
head = tail = 0 ;
REP ( i , MAXW ) {
if ( next[root][i] == -1 )
next[root][i] = root ;
else {
Q[tail ++] = next[root][i] ;
addedge ( root , next[root][i] , 1 , word[next[root][i]] ) ;
fail[next[root][i]] = root ;
}
}
while ( head != tail ) {
int now = Q[head ++] ;
REP ( i , MAXW ) {
if ( next[now][i] == -1 ) {
next[now][i] = next[fail[now]][i] ;
}
else {
fail[next[now][i]] = next[fail[now]][i] ;
addedge ( now , next[now][i] , 1 , word[next[now][i]] ) ;
Q[tail ++] = next[now][i] ;
}
}
}
REP ( i , P )
if ( fail[i] != root )
addedge ( i , fail[i] , 0 , word[fail[i]] ) ;
}
int zhuliu () {
int res = 0 ;
NV = P ;
while ( 1 ) {
clear ( In , INF ) ;
REP ( i , NE ) {
int u = E[i].u ;
int v = E[i].v ;
if ( u != v && In[v] > E[i].c ) {
In[v] = E[i].c ;
pre[v] = u ;
ans[E[i].now] = i ;
}
}
int cnt = 1 ;
clear ( idx , -1 ) ;
clear ( vis , 0 ) ;
pre[0] = 0 ;
idx[0] = 0 ;
In[0] = 0 ;
REP ( i , NV ) {
res += In[i] ;
int v = i ;
while ( vis[v] != i && idx[v] == -1 && v != 0 ) {
vis[v] = i ;
v = pre[v] ;
}
if ( idx[v] == -1 && v != 0 ) {
for ( int u = pre[v] ; u != v ; u = pre[u] )
idx[u] = cnt ;
idx[v] = cnt ++ ;
}
}
if ( cnt == 1 )
break ;
REP ( i , NV )
if ( idx[i] == -1 )
idx[i] = cnt ++ ;
REP ( i , NE ) {
int u = E[i].u ;
int v = E[i].v ;
E[i].u = idx[u] ;
E[i].v = idx[v] ;
if ( idx[u] != idx[v] )
E[i].c -= In[v] ;
}
NV = cnt ;
}
return res ;
}
void add ( int u , int v , int word , int f ) {
edge[cntE].v = v ;
edge[cntE].f = f ;
edge[cntE].word = word ;
edge[cntE].n = H[u] ;
H[u] = cntE ++ ;
}
void dfs ( int u ) {
for ( int i = H[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
num[v] = ++ cnt ;
printf ( "%d -> %d %c\n" , num[u] , num[v] , edge[i].word + 'a' ) ;
dfs ( v ) ;
}
}
int find ( int x ) {
return p[x] == x ? x : ( p[x] = find ( p[x] ) ) ;
}
void solve () {
init () ;
REP ( i , n ) {
scanf ( "%s" , buf ) ;
insert ( buf ) ;
}
build () ;
int res = zhuliu () + 1 ;
printf ( "%d\n0\n" , res ) ;
REPF ( i , 0 , P - 1 )
p[i] = i ;
REPF ( i , 1 , P - 1 )
if ( !E[ans[i]].f ) {
printf ( "-------%d -> %d\n" , E[ans[i]].now , E[ans[i]].pre ) ;
p[E[ans[i]].now] = E[ans[i]].pre ;
}
REPF ( i , 1 , P - 1 )
find ( i ) ;
REPF ( i , 1 , P - 1 )
printf ( "%d -> %d\n" , p[E[ans[i]].pre] , p[E[ans[i]].now] ) ;
REPF ( i , 1 , P - 1 )
if ( p[E[ans[i]].pre] != p[E[ans[i]].now] && !mark[p[E[ans[i]].pre]][p[E[ans[i]].now]] ) {
mark[p[E[ans[i]].pre]][p[E[ans[i]].now]] = 1 ;
add ( p[E[ans[i]].pre] , p[E[ans[i]].now] , E[ans[i]].word , E[ans[i]].f ) ;
}
num[0] = ++ cnt ;
dfs ( 0 ) ;
}
} ;
Trie c ;
int main () {
while ( ~scanf ( "%d" , &c.n ) )
c.solve () ;
return 0 ;
}