zoukankan      html  css  js  c++  java
  • HDU3247 AC自动机+dp

    题意:给出n个资源,m个病毒,将资源串拼接成一个串,必须包含所有的资源串,可以重叠,但是不能包含病毒,问最小的长度为多少

    题解:所有串建AC自动机。对以资源串结尾的结点跑bfs,求出到其他资源串结尾的最小距离。当前结点的fail结点不能入队列,因为当前结点读下一个字符可能会遇到禁止字符串,而fail结点读相同字符可能没有遇到禁止字符串...所以每次直接将nex的可行结点入队列。(fail结点不入队列,直接设为与当前结点距离为0应该也是可行的,然而WA了)很多时候我都开始质疑数据问题了...

    如果当前字符串本身包含另一个资源串,那距离不应当是0吗?有一种解释是dp的时候经过 | 操作就可以了。

      1 #include <bits/stdc++.h>
      2 #include <cstdio>
      3 #include <iostream>
      4 #include <algorithm>
      5 #define ll long long
      6 #define lson l, m, rt<<1
      7 #define rson m+1, r, rt<<1|1
      8 #define st first
      9 #define nd second
     10 #define mp make_pair
     11 #define pii pair<int, int>
     12 #define gg puts("gg");
     13 #define local
     14 //#define out1
     15 using namespace std;
     16 const int N  = 6e4+10;
     17 const int inf = 0x3f3f3f3f;
     18 int id(char c){
     19     return c == '1';
     20 }
     21 struct Tire{
     22     int nex[N][2], fail[N],end[N];
     23     int root, L;
     24     int node[15], tot;
     25     int newnode(){
     26         nex[L][0] = nex[L][1] = -1;
     27         end[L] = 0;
     28         return L++;
     29     }
     30     void init(){
     31         L = tot = 0;
     32         root = newnode();
     33     }
     34     void insert(char* s, int tag){
     35         int now = root;
     36         for(int i = 0; s[i]; i++){
     37             int p = id(s[i]);
     38             if(nex[now][p] == -1)
     39                 nex[now][p] = newnode();
     40             now = nex[now][p];
     41         }
     42         if(tag >= 0)
     43             end[now] |= 1<<tag;
     44         else end[now] = -1;
     45     }
     46     void build(){
     47         queue<int> Q;
     48         fail[root] = root;
     49         for(int i = 0; i < 2; i++){
     50             int& u = nex[root][i];
     51             if(u == -1)
     52                 u = root;
     53             else{
     54                 fail[u] = root;
     55                 Q.push(u);
     56             }
     57         }
     58         while(!Q.empty()){
     59             int now = Q.front();
     60             Q.pop();
     61             for(int i = 0; i < 2; i++){
     62                 int& u = nex[now][i];
     63                 if(u == -1)
     64                     u = nex[ fail[now] ][i];
     65                 else{
     66                     fail[u] = nex[ fail[now] ][i];
     67                     end[u] |= end[ fail[u] ];
     68                     Q.push(u);
     69                 }
     70             }
     71         }
     72     }
     73 };
     74 Tire ac;
     75 char s[N];
     76 void gmin(int& a, int b){
     77     if(a > b) a = b;
     78 }
     79 int dis[N], ve[N], tot;
     80 int w[555][555];
     81 
     82 void bfs(int node, int i){
     83     memset(dis, 0x3f, sizeof(dis));
     84     queue<int> Q;
     85     Q.push(node); dis[node] = 0;
     86     int s = 0;
     87 
     88     #ifdef out1
     89     int j = node;
     90     while(ac.fail[j] != ac.root){
     91         j = ac.fail[j];
     92         dis[j] = 0;
     93     }
     94     dis[j] = 0;
     95     #endif
     96 
     97     while(!Q.empty()){
     98         int sz = Q.size();
     99         s++;
    100         while(sz--){
    101             int f = Q.front(); Q.pop();
    102             for(int j = 0; j < 2; j++){
    103                 int to = ac.nex[f][j];
    104                 if(dis[to] < inf||ac.end[to] < 0) continue ;
    105                 Q.push(to);
    106                 dis[to] = s;
    107 
    108                 #ifdef out1
    109                 while(ac.fail[to] != ac.root&&dis[ac.fail[to]] == inf){
    110                     to = ac.fail[to];
    111                     dis[to] = s;
    112                 }
    113                 #endif
    114             }
    115         }
    116     }
    117     for(int j = 0; j < tot; j++)
    118         w[i][j] = dis[ ve[j] ];
    119 }
    120 int dp[555][1<<11];
    121 int main(){
    122     #ifdef locl
    123     freopen("in", "r", stdin);
    124     #ifdef out1
    125         freopen("out1", "w", stdout);
    126     #else
    127         freopen("out2", "w", stdout);
    128     #endif // out1
    129     #endif // locl
    130     int n, m, t, ca = 1;
    131     while(~scanf("%d%d", &n, &m), n+m){
    132         ac.init();
    133 
    134         memset(w, 0x3f, sizeof(w));
    135         for(int i = 0; i < n; i++){
    136             w[i][i] = 0;
    137             scanf("%s", s);
    138             ac.insert(s, i);
    139         }
    140         for(int i = 0; i < m; i++){
    141             scanf("%s", s);
    142             ac.insert(s, -1);
    143         }
    144         ac.build();
    145 
    146         tot = 0;
    147         for(int i = 0; i < ac.L; i++)
    148             if(!i||ac.end[i] > 0) ve[tot++] = i;
    149         memset(w, 0x3f, sizeof(w));
    150         for(int i = 0; i < tot; i++)
    151             bfs(ve[i], i);
    152 //        for(int i = 0; i < tot; i++){
    153 //            for(int j = 0; j < tot; j++)
    154 //                printf("%10d ", w[i][j]);
    155 //            puts("");
    156 //        }
    157 
    158         memset(dp, 0x3f, sizeof(dp));
    159         for(int i = 0; i < tot; i++)
    160             dp[i][ ac.end[ve[i]] ] = w[0][i];
    161         for(int i = 0; i < (1<<n); i++){
    162             for(int j = 0; j < tot; j++){
    163                 if( dp[j][i] < 0x3f3f3f3f ) for(int k = 0; k < tot; k++)
    164                     if(j != k&&w[j][k] < 0x3f3f3f3f)
    165                         gmin(dp[k][i|ac.end[ve[k]]], dp[j][i]+w[j][k]);
    166             }
    167         }
    168 
    169 //        for(int i = 0; i < n; i++)
    170 //            for(int j = 0; j < (1<<n); j++)
    171 //                printf("%d %d: %d
    ", i, j, dp[i][j]);
    172 
    173         int ans = inf;
    174         for(int i = 0; i < tot; i++)
    175             ans = min(ans, dp[i][ (1<<n)-1 ]);
    176         printf("%d
    ", ans);
    177     }
    178     return 0;
    179 }
    180 /*
    181 2 2
    182 1110
    183 0111
    184 101
    185 1001
    186 
    187 3 3
    188 0001000
    189 00100
    190 010
    191 11
    192 111
    193 1111
    194 */
  • 相关阅读:
    android 通知栏 notifcation
    通过ResultSet获取到rs的记录数的几种方法
    网上书城随笔
    jdbc 事务
    正则表达式
    String,StringBuffer与StringBuilder的区别??
    Java 之 FileReader FileInputStream InputStreamReader BufferedReader 作用与区
    算法
    呵呵
    Hibernate
  • 原文地址:https://www.cnblogs.com/dirge/p/6012142.html
Copyright © 2011-2022 走看看