1. 程式人生 > >HDU 3247 ac自動機+bfs+狀態壓縮dp

HDU 3247 ac自動機+bfs+狀態壓縮dp

Resource Archiver

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others)
Total Submission(s): 1429    Accepted Submission(s): 418


Problem Description Great! Your new software is almost finished! The only thing left to do is archiving all your n resource files into a big one.
Wait a minute… you realized that it isn’t as easy as you thought. Think about the virus killers. They’ll find your software suspicious, if your software contains one of the m predefined virus codes. You absolutely don’t want this to happen.
Technically, resource files and virus codes are merely 01 strings. You’ve already convinced yourself that none of the resource strings contain a virus code, but if you make the archive arbitrarily, virus codes can still be found somewhere.
Here comes your task (formally): design a 01 string that contains all your resources (their occurrences can overlap), but none of the virus codes. To make your software smaller in size, the string should be as short as possible.
Input There will be at most 10 test cases, each begins with two integers in a single line: n and m (2 <= n <= 10, 1 <= m <= 1000). The next n lines contain the resources, one in each line. The next m lines contain the virus codes, one in each line. The resources and virus codes are all non-empty 01 strings without spaces inside. Each resource is at most 1000 characters long. The total length of all virus codes is at most 50000. The input ends with n = m = 0.
Output For each test case, print the length of shortest string.
Sample Input 2 2 1110 0111 101 1001 0 0
Sample Output 5

題意:給定n個子串,m個病毒串,然後讓合併,使得串儘可能的短,但是不能含有病毒串,

這個題好難,n不超過10,看了別人的思路,先把子串與病毒串插進ac自動機去,子串標記為對應的狀態,病毒串末尾標記為-1,然後把合法的子串節點取出來,然後通過bfs求兩兩之間的

最短路,然後狀態壓縮dp。

程式碼:

/* ***********************************************
Author :xianxingwuguan
Created Time :2014-2-5 17:31:21
File Name :4.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
struct node{
	int next[60010][2],end[60010],fail[60030];
	int root,L;
	int newnode(){
		next[L][0]=next[L][1]=-1;
		end[L++]=0;
		return L-1;
	}
	void init(){
		L=0;
		root=newnode();
	}
	void insert(char *str,int id){
		int len=strlen(str);
		int now=root;
		for(int i=0;i<len;i++){
			int p=str[i]-'0';
			if(next[now][p]==-1)
				next[now][p]=newnode();
			now=next[now][p];
		}
		if(id==-1)
			end[now]=-1;
		else end[now]|=(1<<id);
	}
	void build(){
		queue<int> q;
		fail[root]=root;
		for(int i=0;i<2;i++){
			if(next[root][i]==-1)
				next[root][i]=root;
			else {
				fail[next[root][i]]=root;
				q.push(next[root][i]);
			}
		}
		while(!q.empty()){
			int now=q.front();q.pop();
			if(end[fail[now]]==-1)end[now]=-1;
			else end[now]|=end[fail[now]];
			for(int i=0;i<2;i++){
				if(next[now][i]==-1)
					next[now][i]=next[fail[now]][i];
				else {
					fail[next[now][i]]=next[fail[now]][i];
					q.push(next[now][i]);
				}
			}
		}
	}
	int dp[1<<10][60],dis[60][60],pnt[100],cnt,que[100010],dist[100000];
	void bfs(int s){
		for(int i=0;i<L;i++)
			dist[i]=INF;
		dist[pnt[s]]=0;
		int front=0,rear=0;
		que[rear++]=pnt[s];
		while(front<rear){
			int now=que[front++];
			for(int i=0;i<2;i++){
				int u=next[now][i];
				if(end[u]==-1||dist[u]!=INF)
					continue;
				dist[u]=dist[now]+1;
				que[rear++]=u;
			}
		}
		for(int i=0;i<cnt;i++)dis[s][i]=dist[pnt[i]];
	}
	void F1(int n){
         cnt=0;
		 for(int i=0;i<L;i++)
			 if(i==0||end[i]>0)
				 pnt[cnt++]=i;
	//	 cout<<"haha:"<<L<<" "<<cnt<<endl;
		 for(int i=0;i<cnt;i++)bfs(i);
         for(int i=0;i<(1<<n);i++)
			 for(int j=0;j<cnt;j++)
				 dp[i][j]=INF;
		 dp[0][0]=0;
		 for(int i=0;i<(1<<n);i++)
			 for(int j=0;j<cnt;j++){
				 if(dp[i][j]==INF)continue;
				 for(int k=0;k<cnt;k++)
					 dp[i|end[pnt[k]]][k]=min(dp[i|end[pnt[k]]][k],dp[i][j]+dis[j][k]);
			 }
		 int ans=INF;
		 for(int i=0;i<cnt;i++)
			 ans=min(ans,dp[(1<<n)-1][i]);
		 cout<<ans<<endl;
	}

}ac;
char str[10030];
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int i,j,k,m,n;
     while(~scanf("%d%d",&n,&m)){
		 if(n==0&&m==0)break;
		 ac.init();
		 for(i=0;i<n;i++){
			 scanf("%s",str);
			 ac.insert(str,i);
		 }
		 while(m--){
			 scanf("%s",str);
			 ac.insert(str,-1);
		 }
		 ac.build();
		 ac.F1(n);
	 }
     return 0;
}


相關推薦

HDU 3247 ac自動機+bfs+狀態壓縮dp

Resource Archiver Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 100000/100000 K (Java/Others) Total Submission(s): 1429    Ac

BZOJ1195[HNOI2006]最短母串——AC自動機+BFS+狀態壓縮

一行 AC urn printf 最少步數 ron 題意 mes 大寫 題目描述 給定n個字符串(S1,S2,„,Sn),要求找到一個最短的字符串T,使得這n個字符串(S1,S2,„,Sn)都是T的子串。 輸入 第一行是一個正整數n

【HDU2825】Wireless Password【AC自動機狀態壓縮DP

博客 oid display 圖片 pla 遇到 當我 題目 img 題意 題目給出m(m<=10)個單詞,每個單詞的長度不超過10且僅由小寫字母組成,給出一個正整數n(n<=25)和正整數k,問有多少方法可以組成長度為n的文本且最少包含k個給出的單詞。

hdu4057(ac自動機狀態壓縮dp

Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah's Ark, or t

hdu 3247(ac自動機+狀態壓縮dp+最短路)

題意:有n個原始檔也就是n個字串(n<=10 長度<=1000),m種病毒也同樣是m個字串(m<=1000,總長度50000),現在要問最短的串包含所有原始檔但不存在一個子串是病毒的長度,原始檔的串可以重疊存在,所有字串由01組成。 題解:好

HDU 4049 Tourism Planning(狀態壓縮DP

http://acm.hdu.edu.cn/showproblem.php?pid=4049 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int

HDU 3247 Resource Archiver(AC自動機+狀態壓縮dp+最短路BFS

Resource Archiver Time Limit: 20000/10000 MS(Java/Others)    Memory Limit: 100000/100000 K(Java/Others) Total Submission(s): 3230    Ac

HDU 3247 Resource Archiver AC自動機+BFS+dp

Resource Archiver   Great! Your new software is almost finished! The only thing left to do is archiving all your n resource files into a bi

hdu 3681 二分+狀態壓縮dp+bfs

#include<stdio.h> #include<string.h> #include<queue> #include<iostream> using namespace std; #define INF 0x3f3f3f3f int n,m; char m

HDU 1074 Doing Homework 狀態壓縮DP

output -- max 方式 sch adl struct work small 題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=1074 題目大意:小明打完比賽回來補作業,N個作業每個作業有 名字,截止日期,完成所需時間

HDU 3001(狀態壓縮DP

狀態壓縮 printf pri names urn 壓縮 puts -1 路徑 題意:遍歷所有的城市的最短路徑,每個城市最多去兩遍。將城市的狀態用3進制表示。 狀態轉移方程為 dp[NewS][i]=min( dp[NewS][i],dp[S][j]+dis[i][j])

HDU 2825 Wireless Password ( Trie圖 && 狀態壓縮DP )

inline ble 轉移 top hdu max style 全部 新節點 題意 : 輸入n、m、k意思就是給你 m 個模式串,問你構建長度為 n 至少包含 k 個模式串的方案有多少種 分析 : ( 以下題解大多都是在和 POJ 2778 && POJ

hdu 4856 Tunnels 狀態壓縮dp

con 通道 panel follow span scan urn left cit Tunnels Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

HDOJ--3001--Travelling(狀態壓縮DP+bfs

介紹 string memset con 代碼 bsp size lin 需要 介紹這道題和3311差不多,只需將二進制換為三進制就好,但對於在做3311時用的是自頂向下方法做的話,上一題的模板都不能套了,還得換個思路。 題意 N個城市,M條路(有重邊,無向圖),x->

HDOJ--3681--Prison Break(BFS預處理+狀態壓縮DP

-s cin pos hdoj con 多少 電源 too 最大的 題意 F--起點 S--空格 G--能量池,只能充一次電,充完之後G變為S,也可已選擇不充而當成普通的S D--激光區,不能走 Y--電源開關 M被關在一所監獄之中,F為起點,每走一步(上下左右)消耗1節能

HDU-4511-ac自動機+dp

當前 %d debug 保留 說明 必須 php cal pre 小明系列故事——女友的考驗 Time Limit: 500/200 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Sub

HDU 4539 鄭廠長系列故事——排兵佈陣(狀態壓縮DP

鄭廠長系列故事——排兵佈陣 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define N

hdu 3341 AC自動機+DP

這道題就是給你N個單詞,一個字串,問你將這個字串重排,能組成包含單詞次數最多的字串有多長。這道題的DP方程有點意思,因為只有四個字元ACGT,字串的長度不超過40,所以我們可以dp[i][a][b[][c][d],表示匹配了i個字元,用了分別用了a,b,c,d個ACGT,能包含的最多的單

HDU 2457 AC自動機+DP

這道題好像讓我對AC自動機的失配指標有了一個新的認識。 Fail指標的求法: Fail指標用BFS來求得,對於直接與根節點相連的節點來說,如果這些節點失配,他們的Fail指標直接指向root即可,其他節點其Fail指標求法如下: 假設當前節點為father,其孩子節點記為child。求c