HDU3247 Resource Archiver(AC自动机+DP)
来源:互联网 发布:最好的搏击软件 编辑:程序博客网 时间:2024/06/05 15:34
HDU3247 Resource Archiver(AC自动机+DP)
http://acm.hdu.edu.cn/showproblem.php?pid=3247
题意:给你n个模板串和m个病毒串,要你设计一个01串,要求该串包含所有的模板串,但是不包含任何一个病毒串,问你这个01串最短长度?
分析:令dp[i][s]=x表示当前在自动机的i节点,并且走过了集合s中的所有模板,且不经过任意病毒串的最小行走距离是x.
dp[i][s]=min( dp[k][s-{x}]+1 ) k和i都不是病毒串尾节点,且从k能到i节点并且i节点是x号模板.
初值为dp[0][0]=0,其他dp=-1.
最终我们所求为:dp[i][(1<<n)-1] i节点不是病毒节点.
AC自动机要维护match[i]=1表示i节点(或其后缀)是病毒.
还要维护val[i]=s,表示i节点(或其后缀)覆盖了集合s中的模板.
最后递推的时候以s从小到大递推,且要先判断match[i],如果match[i]==0再用当前s|val[i]
但是该题如果这么算的话可能要花9s多,其实对于我们有效的节点只是那些value[i]!=0的节点(因为value[i]=0的节点,就算你走上去也不会改变任何的dp值),我们只需要把这些节点分离出来,然后建立一张最短路径图,并且将dp建立在这个图的基础上就可以大大优化计算.dp[i][s]=x表示当前在新图上的i节点,且包含模板的情况为s,且不经过病毒串的需要行走最短距离为x.
注意:虽然模板串最多只有10个,但是新图G的节点并不是最多10个,可能有超过10个的.但是HDU这题的测试数据中没有出现这种情况,尔可能测试数据比较弱,下面的这个例子输出-1的程序也能过.说明HDU给的那10个模板一般不会出现交叉重叠的情况.
比如下面这个例子:
10 2
00
11
000
111
0000
1111
01000
10111
100000
011111
111111111111111111111
000000000000000000000
答案应该是14,而不是-1.因为串10111110100000是符合要求的串.且由上面的模板生成的G图节点数要超过10个的.
AC代码:62ms
//用自动机中的非病毒模板尾节点建立一张最短路新图G#include<cstdio>#include<cstring>#include<queue>#include<algorithm>using namespace std;const int maxnode=60000+100;const int sigma_size=2;int cnt,pos[110];//pos[i]=j表示新图中i节点在自动机中的节点标号int dis[maxnode];//dis[i]表新图当前节点到i节点的单源最短距离,用于BFS计算单源最短路径int G[110][110];//G[i][j]=x表示新图中有效节点i到j的距离,注意新图的节点可能1int dp[110][1000+100];int N,M;char str[50000+100];int MIN(int a,int b){ if(a<0 || b<0) return a<b? b:a; else return a<b? a:b;}struct AC_Automata{ int ch[maxnode][sigma_size]; int f[maxnode]; int match[maxnode];//判断是否病毒 int val[maxnode];//包含的单词集合 int sz; void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); f[0]=match[0]=val[0]=0; } void insert(char *s,int v) { int n=strlen(s),u=0; for(int i=0;i<n;i++) { int id=s[i]-'0'; if(ch[u][id]==0) { ch[u][id]=sz; memset(ch[sz],0,sizeof(ch[sz])); match[sz]=0; val[sz++]=0; } u=ch[u][id]; } if(v!=-1) val[u] = 1<<v; else match[u]=1; } void getFail() { queue<int> q; for(int i=0;i<sigma_size;i++) { int u=ch[0][i]; if(u) { f[u]=0; q.push(u); } } while(!q.empty()) { int r=q.front();q.pop(); for(int i=0;i<sigma_size;i++) { int u=ch[r][i]; if(!u) { ch[r][i]=ch[f[r]][i]; continue; } q.push(u); int v=f[r]; while(v && ch[v][i]==0) v=f[v]; f[u]=ch[v][i]; match[u] |= match[f[u]]; val[u] |= val[f[u]]; } } } void path(int k) { queue<int> q; q.push(pos[k]); memset(dis,-1,sizeof(dis)); dis[pos[k]]=0; while(!q.empty()) { int r=q.front();q.pop(); for(int i=0;i<sigma_size;i++) { int u=ch[r][i]; if(match[u]) continue;//病毒串 if(dis[u]!=-1)continue;//最短距离已经算出来了 dis[u] = dis[r] +1; q.push(u); } } for(int i=0;i<cnt;i++) G[k][i]=dis[pos[i]]; } int solve() { //建立新的最短路图 cnt=1; pos[0]=0; for(int i=1;i<sz;i++)if(val[i]) pos[cnt++]=i; for(int i=0;i<cnt;i++) path(i); //DP递推 memset(dp,-1,sizeof(dp)); dp[0][0]=0; for(int st=0;st<(1<<N);st++) { for(int i=0;i<cnt;i++)if(dp[i][st]!=-1) { for(int j=0;j<cnt;j++)if(G[i][j]!=-1) { int state= st|val[pos[j]]; if(dp[j][state]== -1) dp[j][state] = dp[i][st]+G[i][j]; else dp[j][state] =min(dp[j][state], dp[i][st]+G[i][j]); } } } int ans=-1; for(int i=0;i<cnt;i++) ans = MIN(ans,dp[i][(1<<N)-1]); return ans; }}ac;int main(){ while(scanf("%d%d",&N,&M)==2&&N&&M) { ac.init(); for(int i=0;i<N;i++) { scanf("%s",str); ac.insert(str,i); } for(int i=0;i<M;i++) { scanf("%s",str); ac.insert(str,-1); } ac.getFail(); printf("%d\n",ac.solve()); }}
- HDU3247 Resource Archiver(AC自动机+DP)
- hdu3247 Resource Archiver AC自动机+状态压缩DP
- hdu3341 Resource Archiver AC自动机+DP
- Resource Archiver hdu3247
- HDU3247 Resource Archiver
- HDU 3247 Resource Archiver(AC自动机+BFS+状态DP)
- hdu 3247 Resource Archiver(AC自动机+状压DP)
- 【ZOJ】 3190 Resource Archiver AC自动机+BFS预处理+DP
- [AC自动机+spfa+状压dp] hdu 3247 Resource Archiver
- hdu 3247 Resource Archiver(AC自动机+BFS+DP)
- hdu 3247 Resource Archiver (ac自动机+BFS+状压dp)
- HDU 3247 Resource Archiver[AC自动机+最短路+dp]
- HDU 3247 Resource Archiver(AC自动机+BFS+状态DP)
- HDU 3247-Resource Archiver(AC自动机+BFS+DP)
- HDU3247-(AC自动机+spfa+状压dp)
- 【AC自动机】 HDOJ 3247 Resource Archiver
- AC自动机+状态压缩dp+BFS求最短路+hdu3247
- HDOJ-3427 & ZOJ-3190 Resource Archiver AC自动机压缩状态DP..
- [黑马程序员]tcpdemo3
- Oracle循环语句
- 在自己的电脑上搭建服务器,发布自己的网站(学习之用)
- 集合类型 (python)
- 在ORACLE存储过程中创建临时表
- HDU3247 Resource Archiver(AC自动机+DP)
- 闰年判断
- js中生成json对象生成动态表格
- 杭电 1248 寒冰王座
- Mysql sql查询时 if 的用法
- 三大Java 虚拟机垃圾回收机制的比较(HotSpot, JRockit, IBM JVM)
- 多线程调试方法
- 序列之一 字符串 (python)
- CSDN发表博文十大注意事项