• 【HDU3247】 Resource Archiver(DP+AC自动机+最短路)


    Resource Archiver
    Time Limit: 10000MS   Memory Limit: 100000KB   64bit IO Format: %I64d & %I64u

    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个病毒,将资源串拼接成一个串,必须包含所有的资源串,可以重叠,但是不能包含病毒。问最小的长度为多少。

    【分析】

      良心题解:http://blog.csdn.net/woshi250hua/article/details/8021283

                   

      · 一开始要想到DP,这是最简单的一步。而且n很小明显是状压,再用一维记录一下最后一个拼接的串。

           即d[i][j]表示现在已经拼接的串集合为i,最后一个串为j的最小费用。

      转移方程->d[i+(1<<k-1)][k]=min{d[i+(1<<k-1)][k],d[i][j]+cost[j][k]}

      转移方程是很容易想的,重点就是求cost[j][k]。

      暴力的话,目测是10*10*1000*1000,有点慢- -。

      所以,要用到优美的性质才行。

      把两种串都建在AC自动机里,打上不同标记,然后按上面所说的沿着next向下走。

      理解了很久这个沿着next向下走的过程之后,我觉得意思应该是这样:

      

      a串和b串连接有很多种方式,其实可以转换成 -> 自己生成一个串,使得前缀是a串,后缀是b串。(如上图第一种情况)

      之前做生成串的题目都是在图上沿nest走的,这样只要不走到危险节点,就不会出现病毒串(fail的优美性质)。

      所以,我们就可以利用这种方法求出拼接且不含危险串的串了。

      要让这个拼接串长度最小,也就是走的从a的末尾节点走到b的末尾节点的路程最小。(因为答案为a串长度+走的步数,而a串长度一定)

      就是一个最短路。

      

      其实感觉有一个小小的BUG,就是无论a,b串怎么拼都含病毒串,他会输出一个大于l[a]+l[b]的数,相当于在a、b串中乱填东西,使得不含病毒串(如上图第二种情况)。这样就与“拼接”的含义不符了。

      你可以简单的判断一下之类的,但是我没有判断也A了。可能是正确的最优解覆盖了它的原因。

      AC自动机要建60000不是50000。(一开始RE了~~)

    代码如下:

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxn 60010
      9 #define Maxl 1200
     10 #define Mn 20
     11 #define INF 0xfffffff
     12 #define Mod 20090717
     13 
     14 int n,m;
     15 char s[Maxl];
     16 
     17 struct node
     18 {
     19     // int cnt;
     20     int fail,mark;
     21     int son[3];
     22 }t[Maxn];int tot;
     23 // int num;
     24 int p[Mn],sl[Mn];
     25 
     26 void upd(int x)
     27 {
     28     // t[x].cnt=0;
     29     t[x].mark=0;
     30     memset(t[x].son,0,sizeof(t[x].son));
     31 }
     32 
     33 int mymin(int x,int y) {return x<y?x:y;}
     34 int mymax(int x,int y) {return x>y?x:y;}
     35 
     36 void read_trie(int tk)
     37 {
     38     scanf("%s",s+1);
     39     int len=strlen(s+1);
     40     if(tk!=-1) sl[tk]=len;
     41     int now=0;
     42     for(int i=1;i<=len;i++)
     43     {
     44         int ind=s[i]-'0'+1;
     45         if(!t[now].son[ind]) 
     46         {
     47             t[now].son[ind]=++tot;
     48             upd(tot);
     49         }
     50         now=t[now].son[ind];
     51         if(i==len) 
     52         {
     53             if(tk==-1) t[now].mark=-1;
     54             else t[now].mark=tk,p[tk]=now;
     55         }
     56     }
     57 }
     58 
     59 queue<int > q;
     60 void build_AC()
     61 {
     62     while(!q.empty()) q.pop();
     63     q.push(0);
     64     while(!q.empty())
     65     {
     66         int x=q.front();q.pop();
     67         for(int i=1;i<=2;i++) 
     68         {
     69             if(t[x].son[i])
     70             {
     71                 t[t[x].son[i]].fail=x?t[t[x].fail].son[i]:0;
     72                 q.push(t[x].son[i]);
     73             }
     74             else t[x].son[i]=t[t[x].fail].son[i];
     75         }
     76         // t[x].mark+=t[t[x].fail].mark;
     77     }
     78 }
     79 
     80 int dis[Mn][Maxn];
     81 bool inq[Mn];
     82 void spfa(int x)
     83 {
     84     while(!q.empty()) q.pop();
     85     memset(dis[x],63,sizeof(dis[x]));
     86     memset(inq,0,sizeof(inq));
     87     dis[x][p[x]]=0;
     88     q.push(p[x]);inq[p[x]]=1;
     89     while(!q.empty())
     90     {
     91         int now=q.front();
     92         for(int i=1;i<=2;i++) if(t[t[now].son[i]].mark!=-1)
     93         {
     94             if(dis[x][t[now].son[i]]>dis[x][now]+1)
     95             {
     96                 dis[x][t[now].son[i]]=dis[x][now]+1;
     97                 if(!inq[t[now].son[i]])
     98                 {
     99                     inq[t[now].son[i]]=1;
    100                     q.push(t[now].son[i]);
    101                 }
    102             }
    103         }
    104         q.pop();inq[now]=0;
    105     }
    106 }
    107 void init()
    108 {
    109     tot=0;upd(0);
    110     for(int i=1;i<=n;i++)
    111     {
    112         read_trie(i);
    113     }
    114     for(int i=1;i<=m;i++) read_trie(-1);
    115     build_AC();
    116     for(int i=1;i<=n;i++)
    117     {
    118         spfa(i);
    119     }
    120 }
    121 
    122 bool check(int x,int y,int z)
    123 {
    124     // if(x==0&&y==0&&z==0) return 1;
    125     // if(y==0||z==0) return 0;
    126     if(((1<<y-1)&z)==0) return 0;
    127     int h=0;
    128     for(int i=1;i<=n;i++)
    129     {
    130         if((1<<i-1)&z) h++;
    131     }
    132     if(h==x) return 1;
    133     return 0;
    134 }
    135 
    136 int f[Maxl][Mn];
    137 void dp()
    138 {
    139     memset(f,63,sizeof(f));
    140     // f[0][0]=0;
    141     for(int i=1;i<=n;i++) f[1<<i-1][i]=sl[i];
    142     for(int i=1;i<n;i++)
    143      for(int j=1;j<=n;j++)
    144       for(int k=1;k<=(1<<n)-1;k++) if(check(i,j,k))
    145       {
    146           if(f[k][j]>INF) continue;
    147           for(int l=1;l<=n;l++) if((k&(1<<l-1))==0)
    148           f[k+(1<<l-1)][l]=mymin(f[k+(1<<l-1)][l],f[k][j]+dis[j][p[l]]);
    149       }
    150     int ans=INF;
    151     for(int i=1;i<=n;i++) ans=mymin(ans,f[(1<<n)-1][i]);
    152     printf("%d
    ",ans);
    153 }
    154 
    155 int main()
    156 {
    157     int kase=0;
    158     while(1)
    159     {
    160         scanf("%d%d",&n,&m);
    161         if(n==0&&m==0) break;
    162         init();
    163         dp();
    164     }
    165     return 0;
    166 }
    [HDU3247]

    2016-07-13 09:55:14

  • 相关阅读:
    java语法基础(总结)
    ZookeeperclientAPI之创建会话(六)
    对A轮的追逐变得越加狂热,当前距离互联网泡沫到底有多近?
    Java集合(一):Java集合概述
    深入了解Cookie(1)------selenium2进行Cookie操作的前奏
    Cocos2d-X开发中国象棋《九》走棋规则
    java中request,application,session三个域及参数简单示例
    在多浏览器使用JS复制内容到剪切板,无需插件
    初学structs2,结果类型简单示例
    使用servletAPI三种方式简单示例
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5665802.html
Copyright © 2020-2023  润新知