hdu 3247 Resource Archiver

hdu 3247 Resource Archiver

有点难想,要把资源串和病毒串一起建到Trie图上(节点数这时是6W了,而不是5W)。要充分理解题目所给的,资源串不包含病毒串这个条件。由n的范围1-10,很容易想到是用状态压缩dp去接字符串,关键是怎么定义状态,这里我就把我的状态定义先给出来,用dp[i][j]表示j状态,以第i个字符串结尾的最小长度。往下接一个k的话,我们要知道j跟k相接时,不包含病毒串能接出的最小长度是多少。那么,我们就预先要处理出len[i][j],表示对于i资源串后面接j时,不包含病毒串,能接出的最小长度是多少。对于所有的i,找到它所在的节点,做一次spfa,就能得到它到所有节点的最短距离,那么与j相接的最短要增加的长度就是i所在的节点到j所在的节点的最短距离,这个复杂度是10*6w左右,还是可以接受的。最后就是状态压缩dp推一下了,这个还是蛮简单的。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std ;

const int maxn = 66666 ;
const int INF = maxn<<2 ;
int pos[15] , cnt ;
int dp[12][1<<12] ;

int min ( int a , int b ) { return a < b ? a : b ; }

struct Que
{
    int tail , head ;
    int q[100005] ;
    void init ()
    {
        head = 1 , tail = 0 ;
    }
    bool empty ()
    {
        return head > tail ;
    }
    int front ()
    {
        return q[head] ;
    }
    void pop ()
    {
        head ++ ;
    }
    void push ( int x )
    {
        q[++tail] = x ;
    }
} Q , Q1 ;
class AC_auto
{
private :
    int tot , c[2][maxn] , id[maxn] , fail[maxn] ;
    int dis[maxn] , len[15][15] , vis[maxn] , fuck[maxn] ;
    int new_node ()
    {
        fail[tot] = id[tot] = 0 ;
        c[0][tot] = c[1][tot] = 0 ;
        return tot ++ ;
    }
public :
    void init ()
    {
        tot = cnt = 0 ;
        Q.init () ;
        new_node () ;
    }
    void insert ( char *s , int v , int flag )
    {
        int now = 0 ;
        for ( ; *s ; s ++ )
        {
            int k = *s - '0' ;
            if ( !c[k][now] ) c[k][now] = new_node () ;
            now = c[k][now] ;
        }
        if ( flag ) pos[++cnt] = now , fuck[now] = v ;
        else id[now] = 1 ;
    }
    void get_fail ()
    {
        int i , u = 0 , j , e ;
        for ( i = 0 ; i < 2 ; i ++ ) if ( c[i][u] ) Q.push ( c[i][u] ) ;
        while ( !Q.empty () )
        {
            u = Q.front () ;
            Q.pop () ;
            for ( i = 0 ; i < 2 ; i ++ )
            {
                if ( c[i][u] )
                {
                    e = c[i][u] ;
                    fail[e] = c[i][fail[u]] ;
                    id[e] |= id[fail[e]] ;
                    Q.push ( e ) ;
                }
                else c[i][u] = c[i][fail[u]] ;
            }
        }
    }
    void spfa ( int u )
    {
        int i , j , e ;
        for ( i = 0 ; i <= tot ; i ++ ) vis[i] = 0 , dis[i] = INF ;
        Q1.init () ;
        Q1.push ( u ) , vis[u] = 1 ;
        dis[u] = 0 ;
        while ( !Q1.empty () )
        {
            u = Q1.front () ;
            Q1.pop () ;
            vis[u] = 0 ;
            for ( i = 0 ; i < 2 ; i ++ )
            {
                e = c[i][u] ;
                if ( !id[e] && dis[e] > dis[u] + 1 )
                {
                    dis[e] = dis[u] + 1 ;
                    if ( !vis[e] )
                    {
                        vis[e] = 1 ;
                        Q1.push ( e ) ;
                    }
                }
            }
        }
    }
    void init ( int maxl )
    {
        int i , j ;
        for ( i = 0 ; i <= cnt ; i ++ )
            for ( j = 0 ; j <= cnt ; j ++ )
                len[i][j] = INF ;
        for ( i = 0 ; i <= cnt ; i ++ )
            for ( j = 0 ; j <= maxl ; j ++ )
                dp[i][j] = INF ;
        for ( i = 1 ; i <= cnt ; i ++ )
            dp[i][1<<(i-1)] = fuck[pos[i]] ;
    }
    void DP ( int maxl )
    {
        int i , j , k ;
        for ( i = 0 ; i <= maxl ; i ++ )
            for ( j = 1 ; j <= cnt ; j ++ )
                if ( i & ( 1 << ( j - 1 ) ) )
                {
                    for ( k = 1 ; k <= cnt ; k ++ )
                        if ( ! ( i & ( 1 << ( k - 1 ) ) ) )
                            dp[k][i|(1<<(k-1))] = min ( dp[k][i|(1<<(k-1))] , dp[j][i] + len[j][k] ) ;
                }
    }
    int work ()
    {
        int i , j , k , l ;
        int maxl = ( 1 << cnt ) - 1 ;
        init ( maxl ) ;
        for ( i = 1 ; i <= cnt ; i ++ )
        {
            spfa ( pos[i] ) ;
            for ( j = 1 ; j <= cnt ; j ++ )
                len[i][j] = dis[pos[j]] ;
        }
        DP ( maxl ) ;
        int ans = INF ;
        for ( i = 1 ; i <= cnt ; i ++ )
            ans = min ( ans , dp[i][maxl] ) ;
        return ans ;
    }
} ac ;

char s[1111] ;

int main ()
{
    int n , m ;
    while ( scanf ( "%d%d" , &n , &m ) != EOF )
    {
        if ( n == 0 && m == 0 ) break ;
        ac.init () ;
        while ( n -- )
        {
            scanf ( "%s" , s ) ;
            int l = strlen ( s ) ;
            ac.insert ( s , l , 1 ) ;
        }
        while ( m -- )
        {
            scanf ( "%s" , s ) ;
            ac.insert ( s , 0 , 0 ) ;
        }
        ac.get_fail () ;
        printf ( "%d\n" , ac.work () ) ;
    }
}
/*
2 3
10101
00011
000110101
0001110101
1010100011

2 1
101101
10111
11011

11

10
*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值