HDU 3247 Resource Archiver

题意:给你N个串,M个危险串,求一个最短的串包含N个串但不包含任一个危险串,求最短串长度。

AC自动机+DP。。

预处理出所有合法节点,计算每个串和其他串的最短距离,也就是一个串最少要在后面加几个字母才能包含另外一个串而且不包含危险串。

然后就是经典的TSP问题了。状压DP即可。

Resource Archiver

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


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
 

Source
2009 “NIT Cup” National Invitational Contest
 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define prt(k) cout<<#k"="<<k<<endl;
inline void Max(int& a,int b) { if(a<b) a=b; }
inline void Min(int& a,int b) { if(a>b) a=b; }
const int N=61022;
#define inf 0x3f3f3f3f
const int Char=2;
int ch[N][2],fail[N];
int endr[N];    ///resource
bool endv[N];   ///virus
int root,L;

int newnode() { memset(ch[L],-1,sizeof ch[L]);endv[L]=0; endr[L]=0; return L++; }
void init()
{
    L=0; root=newnode();
}
void insert(char s[],int id)
{
    int n=strlen(s),u=root;
    for(int i=0;i<n;i++)
    {
        int& tmp=ch[u][s[i]-'0'];
        if(tmp==-1) tmp=newnode();
        u=tmp;
    }
    if(id==-1) endv[u]=1;
    else endr[u]|=(1<<id);
}
void BUILD()
{
    queue<int> q;
    for(int i=0;i<Char;i++)
    {
        int& tmp=ch[root][i];
        if(tmp==-1) tmp=root;
        else { fail[tmp]=root; q.push(tmp); }
    }
    while(!q.empty())
    {
        int u=q.front(); q.pop();
        endr[u]|=endr[fail[u]];
        endv[u]|=endv[fail[u]];
        for(int i=0;i<Char;i++)
        {
            int& tmp=ch[u][i];
            if(tmp==-1) tmp=ch[fail[u]][i];
            else { fail[tmp]=ch[fail[u]][i]; q.push(tmp); }
        }
    }
}
char s[N];
int n,m;
int pos[222],tot;
int dis[N],d[211][211];

void spfa(int id)   ///pos[id]
{
    queue<int> q;
    memset(dis,-1,sizeof dis);
    dis[pos[id]]=0;
    q.push(pos[id]);
    while(!q.empty())
    {
        int u=q.front();    q.pop();
        for(int i=0;i<2;i++)
        {
            int v=ch[u][i];
            if(endv[v]==0&&dis[v]==-1)
            {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    for(int i=0;i<tot;i++) d[id][i]=dis[pos[i]];
}
int dp[1033][111];
int main()
{
    while(scanf("%d%d",&n,&m)==2&&n)
    {
        init();
        for(int i=0;i<n;i++) { scanf("%s",s);insert(s,i); }
        for(int i=0;i<m;i++) { scanf("%s",s);insert(s,-1); }
        BUILD();
        tot=0;  ///legal point
        pos[tot++]=root;
        for(int i=0;i<L;i++) if(!endv[i]&&endr[i]>0) pos[tot++]=i;
        for(int i=0;i<tot;i++) spfa(i);
        memset(dp,63,sizeof dp);
        dp[0][0]=0;
        for(int i=0;i<(1<<n);i++)
            for(int j=0;j<tot;j++)
            for(int k=0;k<tot;k++)
        {
            int t=i|endr[pos[k]];
            Min(dp[t][k],dp[i][j]+d[j][k]);
        }
        int res=inf;
        for(int i=0;i<tot;i++) Min(res,dp[(1<<n)-1][i]);
        printf("%d\n",res+1);
    }
}


你可能感兴趣的:(AC自动机)