• poj 1699 Best Sequence (压缩dp)


    先说一下我了解的压缩状态dp吧。

    经典的压缩dp问题是TSP问题: 一个n个点的带权的有向图,求一条路径,使得这条路经过每个点恰好一次,并且路径上边的权值和最小(或者最大)。或者求一条具有这样性质的回路。

    压缩dp问题中存储点集是利用二进制形式,比如 3 = 0000,0000,0000,0011 表示第一个和第二个点在点集中,5 = 0000,0000,0000,0101 表示第一个和第三个点在点集中,以此类推。

    呃,简单来说,就是用一个数表示一种状态,一般n<= 16 或n <= 32 。

    状态转移:如果状态存在,dp[i][j] = 0 ,否则为无穷大.

    1、状态存在:dp[i][j] = min(dp[k][s] + v[s][j] );k表示i集合中去掉了j点的集合,s遍历集合k中的点并且dp[k][s]状态存在,点s到点j有边存在,v[s][j]表示边的权值。

    2、状态不存在,则为无穷大。       最后的结果是: min( dp[( 1<<n ) – 1][j] ) ( 0 <= j < n )

    利用二进制还有一个好处,就是对集合的一些操作可以用位运算来实现,  例如从集合i中去掉点j:  k = i & (~( 1<<j)) 或者 k = i - (1<<j)

    好吧,现在来说说这题;

    题意:给出N个任意长度的字符串,一些字符串的首尾有些字符时相同的,可以相互重叠起来缩短长度,让你求把这N个字符串连起来的最短的长度。

    思路:听说这题可以暴力过,不过没试过,可以求出两个字符串的最长重叠长度,然后全排列。还有好多人用搜索过的,不过我是用的压缩dp,先预处理一下字符串,求出任意两个字符串相连的最大重叠长度,然后用一下压缩dp救过了。

    代码:

    View Code
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <math.h>
    #define  N 24
    #define  M 12
    using namespace std ;
    
    int att[N][N] , len[M] , dp[1<<M][N] ;
    char str[M][N] ;
    int n ;
    
    void cal ( int x , int y )
    {
        int i , j , k ;
        int len1 = len[x] ;
        int len2 = len[y] ;
        int lenx = len1 < len2 ? len1 : len2 ;
        for ( i = lenx - 1 ; i >= 0 ; i-- )
        {
            for ( j = len1 - i - 1 , k = 0 ; j < len1 ; j++ , k++ )
            if ( str[x][j] != str[y][k] )
            break;
            if ( k == i + 1 )
            {
                att[x][y] = k ;
                return ;
                break;
            }
        }
        att[x][y] = 0 ;
    }
    
    int main()
    {
        int cas , i , j , k ;
    
        scanf( "%d" , &cas );
        while( cas-- )
        {
            scanf( "%d" , &n );
            getchar();
            for( i = 0 ; i < n ; i++ )
            {
                scanf( "%s" , str[i] );
                getchar();
                //求出每个字符串长度
                len[i] = strlen( str[i] );
            }
            //预处理,算出任意两个字符串重叠的最大长度
            for ( i = 0 ; i < n ; i++ )
            {
                for ( j = 0 ; j < n ; j++ )
                if ( i != j )
                cal ( i , j );
            }
            memset( dp , -1 , sizeof( dp ));
            //压缩状态dp
            for ( i = 0 ; i < n ; i++ )
            dp[1<<i][i] = len[i] ;
            int np = ( 1<<n ) - 1 ;
            for ( i = 1 ; i <= np ; i++ )
            {
                for( j = 0 ; j < n ; j++ )
                {
                    if ( dp[i][j] == -1 || ( i&( 1<<j )) == 0 )
                    continue ;
                    for ( k = 0 ; k < n ; k++ )
                    {
                        if ( j == k )
                        continue ;
                        if ( i&( 1<<k ))
                        continue ;
                        int tem = i|(1<<k);
                        if ( dp[tem][k] == -1 || dp[i][j] - att[j][k] + len[k] < dp[tem][k] )
                        dp[tem][k] = dp[i][j] - att[j][k] + len[k] ;
                    }
                }
            }
            int minx = -1 ;
            for ( i = 0 ; i < n ; i++ )
            if( minx == -1 || dp[np][i] < minx )
            minx = dp[np][i] ;
            printf( "%d\n" , minx );
        }
        return 0 ;
    }

     

  • 相关阅读:
    UVA 12338
    最短路问题
    菜鸟调错(十)——启动Tomcat报错“Unsupported major.minor version xxx ”
    Servlet总结(一)
    <html>
    Android Developer:Allocation Tracker演示
    H2数据库集群
    安卓通过广播自己主动回填短信验证码
    江湖问题研究-- intent传递有没有限制大小,是多少?
    spring 配置文件被加载两次
  • 原文地址:https://www.cnblogs.com/misty1/p/2627931.html
Copyright © 2020-2023  润新知