首页 > 代码库 > [AC自动机+spfa+状压dp] hdu 3247 Resource Archiver
[AC自动机+spfa+状压dp] hdu 3247 Resource Archiver
题意:
给n个本源串,m个病毒串
求一个最多的长度的单词包含所有的本源串并不包含任意一个病毒串
串均为01串
思路:
只有10个本源串
一开始想的是直接建立完trie图 然后在图上直接spfa
结果发现 dis[60005][1030] 超内存了
这个时候就要想到
其实只有节点的mark值大于0的节点是我们需要用的
就是那些含有状压权值的节点
那么我们先记录下这些节点是哪些
然后发现其实这些不到100个节点
所以跑100遍spfa 求出两两之间的最短路
然后用这个距离 去状压dp
数组就成了 dp[1030][100] 了
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"map" #define inf 0x7fffffff #include"iostream" using namespace std; int triecont; char bd[60021]; struct trie { int mark; //这里如果mark=-1说明不能走 大于0 说明能走到某个单词 int id; trie *next[3],*fail; trie() { mark=id=0; memset(next,0,sizeof(next)); fail=NULL; } }; trie *root,*node[60002]; void init(char *v,int k,int id) { trie *p=root; for(int i=0; v[i]; i++) { int tep=v[i]-'0'; if(p->next[tep]==NULL) { p->next[tep]=new trie(); node[triecont]=p->next[tep]; p->next[tep]->id=triecont++; } p=p->next[tep]; } if(k==0) p->mark=(1<<id); else p->mark=-1; } void getac() { queue<trie*>q; q.push(root); while(!q.empty()) { trie *p=q.front(); q.pop(); for(int i=0; i<2; i++) { if(p->next[i]==NULL) { if(p==root) p->next[i]=root; else p->next[i]=p->fail->next[i]; } else { if(p==root) p->next[i]->fail=root; else p->next[i]->fail=p->fail->next[i]; q.push(p->next[i]); if(p!=root) { if(p->next[i]->mark==-1 || p->next[i]->fail->mark==-1) p->next[i]->mark=-1; else p->next[i]->mark|=p->next[i]->fail->mark; } } } } } struct Node { int id; }; int dis[60001],use[60001]; int useful[222],juli[222][222]; void spfa(int u,int n,int s,int cnt) { queue<Node>q; int i; for(i=0; i<=n; i++) { dis[i]=inf; use[i]=0; } dis[u]=0; use[u]=1; Node now; now.id=u; q.push(now); while(!q.empty()) { Node cur=q.front(); q.pop(); for(i=0; i<2; i++) { int v=node[cur.id]->next[i]->id; if(node[v]->mark==-1) continue; if(dis[v]>dis[cur.id]+1) { dis[v]=dis[cur.id]+1; now.id=v; if(!use[now.id]) { use[now.id]=1; q.push(now); } } } } for(int i=0; i<cnt; i++) juli[s][i]=dis[useful[i]]; } int dp[1300][222]; int main() { int n,m; while(scanf("%d%d",&n,&m),(n+m)) { triecont=0; root=new trie(); node[triecont]=root; root->id=triecont++; for(int i=0; i<n; i++) { char x[1004]; scanf("%s",x); init(x,0,i); } while(m--) { scanf("%s",bd); init(bd,1,1); } getac(); int cnt=0; useful[cnt++]=0; for(int i=1; i<triecont; i++) //找出所有我们需要的节点 { if(node[i]->mark>0) useful[cnt++]=i; } for(int i=0; i<cnt; i++) //每个作为起点 跑一遍spfa { spfa(useful[i],triecont,i,cnt); } for(int i=0; i<cnt; i++) for(int j=0; j<(1<<n); j++) dp[j][i]=inf; dp[0][0]=0; for(int i=0; i<(1<<n); i++) //状压dp { for(int j=0; j<cnt; j++) { if(dp[i][j]==inf) continue; for(int k=0; k<cnt; k++) { int tep=node[useful[k]]->mark|i; if(j==k) continue; if(juli[j][k]==inf) continue; dp[tep][k]=min(dp[tep][k],dp[i][j]+juli[j][k]); } } } int ans=inf; for(int i=0; i<cnt; i++) ans=min(ans,dp[(1<<n)-1][i]); printf("%d\n",ans); } return 0; }
[AC自动机+spfa+状压dp] hdu 3247 Resource Archiver
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。