zoukankan      html  css  js  c++  java
  • HDU3247 Resource Archiver —— AC自动机 + BFS最短路 + 状压DP

    题目链接:https://vjudge.net/problem/HDU-3247

    Resource Archiver

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


    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

    题意:

    给出n个(n<=10)字符串,和m(m<=1000)个单词。求包含所有字符串,并且不包含任何一个单词的长串的最短长度。

    题解:

    1.看到n的大小为10,并且要求包含所有字符串,就很容易想到用状压DP。

    1.1 设dp[status][u]为:当前状态为status(包含了哪些字符串),并且以字符串u结尾的最短长度。设cost[u][v]为:在字符串u后面接上字符串v所需要的最短长度。由于字符串之间可以有重叠,所以cost[u][v]可能小于len[v];由于长串不能包含单词,所以在链接u、v时,之间可能还需要加一些字符以便跳过单词,所以cost[u][v]可能大于len[v]。

    1.2 假如求出了cost数组,那么剩下的就是典型TSP问题了。

    2. 如何求cost数组呢?

    2.1 把n个字符串和m个单词都插入到AC自动机中,并且需要对字符串和单词作相应的标记。

    2.2 对于每个字符串,在自动机上跑最短路,求出当前字符串与其他字符串的最短距离,在跑的时候需要跳过单词。原理:AC自动机各个状态之间的关系构成了一张图。

    代码如下:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <cmath>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <string>
     11 #include <set>
     12 using namespace std;
     13 typedef long long LL;
     14 const double EPS = 1e-6;
     15 const int INF = 2e9;
     16 const LL LNF = 2e18;
     17 const int MOD = 1e5;
     18 const int MAXN = 5e4+1e4+10;
     19 
     20 int n, m;
     21 int Index[MAXN], pos[MAXN], cost[15][15], Len[MAXN];
     22 int dp[1<<11][11];
     23 struct Trie
     24 {
     25     int sz, base;
     26     int next[MAXN][2], fail[MAXN], end[MAXN];
     27     int root, L;
     28     int newnode()
     29     {
     30         for(int i = 0; i<sz; i++)
     31             next[L][i] = -1;
     32         end[L++] = false;
     33         return L-1;
     34     }
     35     void init(int _sz, int _base)
     36     {
     37         sz = _sz;
     38         base = _base;
     39         L = 0;
     40         root = newnode();
     41     }
     42     int insert(char buf[], bool isVirus)
     43     {
     44         int len = strlen(buf);
     45         int now = root;
     46         for(int i = 0; i<len; i++)
     47         {
     48             if(next[now][buf[i]-base] == -1) next[now][buf[i]-base] = newnode();
     49             now = next[now][buf[i]-base];
     50         }
     51         end[now] = isVirus;
     52         return now;
     53     }
     54     void build()
     55     {
     56         queue<int>Q;
     57         fail[root] = root;
     58         for(int i = 0; i<sz; i++)
     59         {
     60             if(next[root][i] == -1) next[root][i] = root;
     61             else fail[next[root][i]] = root, Q.push(next[root][i]);
     62         }
     63         while(!Q.empty())
     64         {
     65             int now = Q.front();
     66             Q.pop();
     67             end[now] |= end[fail[now]];
     68             for(int i = 0; i<sz; i++)
     69             {
     70                 if(next[now][i] == -1) next[now][i] = next[fail[now]][i];
     71                 else fail[next[now][i]] = next[fail[now]][i], Q.push(next[now][i]);
     72             }
     73         }
     74     }
     75 
     76     int query()
     77     {
     78         for(int i = 0; i<(1<<n); i++)
     79         for(int j = 0; j<n; j++)
     80             dp[i][j] = INF;
     81         for(int j = 0; j<n; j++)
     82             dp[1<<j][j] = Len[j];
     83 
     84         for(int i = 0; i<(1<<n); i++)
     85         for(int j = 0; j<n; j++)
     86         {
     87             if(!(i&(1<<j)) || dp[i][j]==INF) continue;
     88             for(int k = 0; k<n; k++)
     89                 if(!(i&(1<<k)) && cost[j][k]!=INF)
     90                     dp[i|(1<<k)][k] = min(dp[i|(1<<k)][k], dp[i][j]+cost[j][k]);
     91         }
     92 
     93         int ret = INF;
     94         for(int i = 0; i<n; i++)
     95             ret = min(ret, dp[(1<<n)-1][i]);
     96         return ret;
     97     }
     98 };
     99 Trie ac;
    100 
    101 int dis[MAXN];
    102 void BFS(int st)
    103 {
    104     queue<int> Q;
    105     while(!Q.empty()) Q.pop();
    106     for(int i = 0; i<ac.L; i++)
    107         dis[i] = INF;
    108     dis[st] = 0;
    109     Q.push(st);
    110     while(!Q.empty())
    111     {
    112         int u = Q.front(); Q.pop();
    113         for(int i = 0; i<ac.sz; i++)
    114         {
    115             int v = ac.next[u][i];
    116             if(dis[v]==INF && !ac.end[v])
    117             {
    118                 dis[v] = dis[u] + 1;
    119                 Q.push(v);
    120             }
    121         }
    122     }
    123     for(int i = 0; i<n; i++)
    124         cost[Index[st]][i] = dis[pos[i]];
    125 }
    126 
    127 char buf[MAXN];
    128 int main()
    129 {
    130     while(scanf("%d%d",&n,&m)&&(n||m))
    131     {
    132         ac.init(2,'0');
    133         memset(Index, -1, sizeof(Index));
    134         for(int i = 0; i<n; i++)
    135         {
    136             scanf("%s", buf);
    137             Len[i] = strlen(buf);
    138             pos[i] = ac.insert(buf, false);
    139             Index[pos[i]] = i;
    140         }
    141         for(int i = 0; i<m; i++)
    142         {
    143             scanf("%s", buf);
    144             ac.insert(buf, true);
    145         }
    146         ac.build();
    147         for(int i = 0; i<n; i++)
    148             BFS(pos[i]);
    149 
    150         int ans = ac.query();
    151         printf("%d
    ", ans);
    152     }
    153 }
    View Code
  • 相关阅读:
    c# 一段生成6位不重复的随机数字码存8万个
    element ui 踩坑记
    Vue node.js 踩坑记
    javascript 异步回调链式调用 promise
    css 盒模型
    vue node.js 引入 linq
    Vue VsCode 项目 launch.json 文件
    node.js 基本语法识记
    Vue 2.0 入门示例识记
    在Windows系统中建立一个隐藏的帐户(在不登录界面显示)
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8461600.html
Copyright © 2011-2022 走看看