zoj 3190 / hdu 3247 Resource Archiver AC自动机+BFS+状态dp

【题意】 给出n个资源串,m个病毒串,要你用这n个资源串组成一个最小的串,使得不包含任何m个病毒串中的一串。

            (2 <= n <= 10, 1 <= m <= 1000),所有串都是非空的01序列,且每个资源串长度不大于1000,病毒串总长小于50000。

            所有资源串都不相同,且不包含包含任何病毒串。

【思路】 先对资源串和病毒串的集合建立AC自动机,然后在trie树上做BFS求出在安全图上每个资源串 

            到其他资源的最短路径,最后做一遍状态压缩dp即可。

            状态: dp[i][j]表示以i结尾的状态为j的最短串

            状态转移: dp[k][j|(1<<k)] = min( dp[k][ j | (1<<k) ] , dp[i][j] + dis[i][k] );

 

     这是ac自动机的经典题,本文参考goAheadtw大牛的解题报告完成。

 

View Code
  1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 using namespace std;
5 const int N=12;
6 const int M=50010+1005*10; //节点个数的最大值
7 const int kind=2;
8 const int INF=0x3fffffff;
9 struct TRIE{
10 int next[kind];
11 int fail,sign;
12 void init()
13 {
14 memset(next,0,sizeof(next));
15 fail=sign=-1; //sign为-1表示既不是病毒也不是资源的串,为-2表示病毒串,大于等于0表示资源串,并表示为资源的id
16 }
17 }trie[M];
18 int que[M],head,tail;
19 int root,tot; //tot是树中节点的个数
20 int n,m;
21
22 int lenr[N],endp[N];
23 int dis[N][N],d[M],mark[M];
24 int dp[N][(1<<10)+10]; //状态压缩dp,dp[i][j]表示以i结尾的状态为j的最短串
25
26 void init()
27 {
28 root=tot=0;
29 trie[0].init();
30 }
31 int insert(char *str,int id)
32 {
33 int i=0,index,r;
34 r=root;
35 while(str[i])
36 {
37 index=str[i]-'0';
38 if(!trie[r].next[index])
39 {
40 trie[++tot].init();
41 trie[r].next[index]=tot;
42 }
43 r=trie[r].next[index];
44 i++;
45 }
46 trie[r].sign=id;
47 return r;
48 }
49 void build_ac_automation()
50 {
51 int i,son,now,p;
52 head=tail=0;
53 que[tail++]=root;
54 trie[root].fail=root;
55 while(head!=tail)
56 {
57 now=que[head++];
58 for(i=0;i<kind;i++)
59 {
60 p=trie[now].fail;
61 if(trie[now].next[i])
62 {
63 son=trie[now].next[i];
64 if(now==root)
65 trie[son].fail=root;
66 else
67 trie[son].fail=trie[p].next[i];
68 que[tail++]=son;
69 }
70 else //增设虚拟节点
71 {
72 if(now==root)
73 trie[now].next[i]=root;
74 else
75 trie[now].next[i]=trie[p].next[i];
76 }
77 }
78 }
79 }
80
81 void BFS(int st)
82 {
83 int i,now,son;
84 head=tail=0;
85 que[tail++]=st;
86 mark[st]=st;
87 d[st]=0;
88 while(head!=tail)
89 {
90 now=que[head++];
91 for(i=0;i<kind;i++)
92 {
93 son=trie[now].next[i];
94 if(trie[son].sign==-2)
95 continue;
96 if(mark[son]!=st)
97 {
98 mark[son]=st;
99 d[son]=d[now]+1;
100 que[tail++]=son;
101 }
102 }
103 }
104 }
105 void DP()
106 {
107 int i,j,k,tmp,sum=(1<<n);
108 for(i=0;i<n;i++)
109 {
110 for(j=0;j<sum;j++)
111 dp[i][j]=INF;
112 dp[i][(1<<i)]=lenr[i];
113 }
114 for(j=1;j<sum;j++)
115 {
116 for(i=0;i<n;i++)
117 {
118 if( !(j&(1<<i)) || dp[i][j]==INF)
119 continue;
120 for(k=0;k<n;k++)
121 {
122 if( j&(1<<k) || dis[i][k]==INF)
123 continue;
124 tmp=dp[i][j]+dis[i][k];
125 if( dp[k][j|(1<<k)]>tmp )
126 dp[k][j|(1<<k)] = tmp;
127 }
128 }
129 }
130 int ans=INF;
131 for(i=0; i<n; i++)
132 {
133 if(ans>dp[i][sum-1])
134 ans=dp[i][sum-1];
135 }
136 printf("%d\n", ans);
137 }
138 void solve()
139 {
140 int i,j;
141 for(i=0;i<n;i++)
142 {
143 for(j=0;j<n;j++)
144 dis[i][j]=INF;
145 dis[i][i]=0;
146 }
147 for(i=0;i<=tot;i++)
148 mark[i]=-1;
149 for(i=0;i<n;i++)
150 {
151 BFS(endp[i]);
152 for(j=0;j<n;j++)
153 {
154 if(mark[endp[j]]!=endp[i])
155 continue;
156 if( d[endp[j]]<dis[i][j] )
157 dis[i][j] = d[endp[j]];
158 }
159 }
160 DP();
161 }
162 int main()
163 {
164 int i;
165 char str[1005];
166 while(scanf("%d%d",&n,&m)!=EOF)
167 {
168 if(!n && !m)
169 break;
170 init();
171 for(i=0;i<n;i++)
172 {
173 scanf("%s",str);
174 lenr[i]=strlen(str);
175 endp[i]=insert(str,i);
176 }
177 for(i=0;i<m;i++)
178 {
179 scanf("%s",str);
180 insert(str,-2);
181 }
182 build_ac_automation();
183 solve();
184 }
185 return 0;
186 }



            


posted on 2012-03-12 19:22  孤星_bin  阅读(385)  评论(0编辑  收藏  举报

导航