• 动态规划:压缩编码;WirelessRouters;


    转载请注明~ 如果有理解不到位或错误的情况,劳烦大神指正,一定感激不尽!

    题目来源:CCF201612-4 压缩编码

      题目的意思是:

      1. 顺序给定文字中n个单词出现的频率(次数);

      2. 对这n个单词进行编码,要求按照字典序;

      3. 在满足字典序的基础上使文字经过编码后的长度最小;

      样例输入:

      5

      1 3 4 2 5

      样例输出:

      34

      思路:条件反射的想到了哈夫曼编码,但由题可知这是不可行的,因为没有保证对单词以字典序编码。在其他博客中发现了用动态规化的方法来解决这个问题:http://blog.csdn.net/zmx19951103/article/details/61200633 。 有一点疑惑的就是,当n为1时,即只有一个单词(编码为0或1),文字经过编码后的最小长度应该就是它的频率w1;但是石子问题中,只有一堆石子的情况下,合并花费为0。在n>1情况下感觉倒是和石子合并是相同的。在此稍加整理。

      子问题:用dp[i][j]表示第i到第j个单词按字典序最小编码的长度。在组合子问题解的过程中,便保持了按字典序编码的要求。如下图1所示。

        当 i = j 时,dp[i][j]是一个叶子结点,它的最小编码就是第i个字母的频率wi:dp[i][j] = wi             ( i = j );

        当 i < j 时,dp[i][j]是一个分支结点,表示从第i个字母到第j个字母由对应频率组成的文本的最小编码长度,添加分支结点表示树加深了一层(见下图),因此:

          dp[i][j] = min( dp[i][j], dp[i][k] + dp[k+1][j] + cost )    ( i <= k < j ) ;

          当dp[i][k]或dp[k+1][j]为叶子结点时,其所在分支深度并没有增加,其对应字母的编码长度也没有增加;当dp[i][k]或dp[k+1][j]为分支结点时,其深度加1,需要将第i到k个字母的频率之各或第k+1到j个字母的频率之和加入到cost中(图2)。

    图1

     

    图2(第二行公式中括号里为cost)

     

    代码如下:

    #include <iostream>
    #include <algorithm>
    
    #define MAX 0x7fffffff
    using namespace std;
    /* run this program using the console pauser or add your own getch, system("pause") or input loop */
    
    int frequence[1001]; // 满足最大的n 
    int sumOfFre[1001];
    int dp[1001][1001]; // should output dp[1][n]
    
    int main(int argc, char** argv) {
        //读取数据 
        int n;
        cin >> n;
        
        sumOfFre[0] = 0;
        frequence[0] = 0;
        
        for( int i = 1; i <= n; i++ )
        {
            cin >> frequence[i];
            
            sumOfFre[i] = sumOfFre[i-1] +  frequence[i];
            
            dp[i][i] = frequence[i]; //下标从 1 ~ n
            //dp[i][i] = 0; //下标从 1 ~ n
        }
        
        
        for( int step = 1; step < n; step++ ) // step=1,得到 dp[1][2],dp[2][3],dp[i][i+step],
                                        // step=2,得到 dp[1][3],dp[2][4],dp[i][i+step],
                                        // ......
                                        // step=n-2,1 <= i < 3 得到 dp[1][n-1],dp[2,n]
                                        // step=n-1,1 <= i < 2 得到 dp[1][n]
        {
            for( int i = 1; i < n-step+1; i++ )
            {
                int j = i + step;
                dp[i][j] = MAX;
                for( int k = i; k < j; k++ )
                {
                    if( k != i && (k+1) != j )
                    {
                        dp[i][j] = min( dp[i][k] + dp[k+1][j] + sumOfFre[j] - sumOfFre[i-1], dp[i][j] );
    //                    cout << "---1   i: " << i << " k: " << k << " j: " << j << " dp[i][j]: " << dp[i][j] << endl;
                    }
                    else if ( k == i && (k+1) != j )
                    {
                        dp[i][j] = min( dp[i][k] + dp[k+1][j] + sumOfFre[j] - sumOfFre[k], dp[i][j] );
    //                    cout << "---2   i: " << i << " k: " << k << " j: " << j << " dp[i][j]: " << dp[i][j] << endl;
                    }
                    else if ( k != i && (k+1) == j )
                    {
                        dp[i][j] = min( dp[i][k] + dp[k+1][j] + sumOfFre[k] - sumOfFre[i-1], dp[i][j] );
    //                    cout << "---3   i: " << i << " k: " << k << " j: " << j << " dp[i][j]: " << dp[i][j] << endl;
                    }
                    else if ( k == i && (k+1) == j )
                    {
                        dp[i][j] = min( dp[i][k] + dp[k+1][j], dp[i][j] );
    //                    cout << "---4   i: " << i << " k: " << k << " j: " << j << " dp[i][j]: " << dp[i][j] << endl;
                    }
                    //dp[i][j] = min( dp[i][k] + dp[k+1][j] , dp[i][j] );
                }
            }
        }
        
        cout << dp[1][n] << endl;
        
        return 0;
    }

    -----------------------------------------------------------------------------------------------------------------------------------------------

    题目来源:一道笔试题 Wireless Routers http://blog.csdn.net/qiangli_strong/article/details/52749860

      题目的意思是:

      1. N个房间,N-1个门;

      2. 每个门连接两个房间,每个房间至少1个门,至多3个门;

      3. 将M个路由器放入N个房间,每个路由器只能覆盖当前房间与相邻房间;

      4. S[i]表示如果第i个屋子有路由器的满意度;

      5. 求一种方案最大化所有屋子的满意度之和。

      样例输入:

      5 1 // 5个房间,1个路由器

      1 2 3 4 5  // 5个房间的满意度

      2 1  // 2号与1号房间有一扇门

      3 2

      4 2

      5 3

      样例输出:

      10

      思路:totalPoint[i][j]表示在前j个房间中放置i个路由器从而达到了最高的满意度总和,有两种情况,

          1. 第j个房间不放路由器,即在前j-1个房间中放了i个路由器;

          2. 第j个房间放路由器,即在前j-1个房间中放了i-1个路由器;

         那么 totalPoint[i][j] = max( totalPoint[i][j-1], totalPoint[i-1][j-1] + gain ),其中gain为第j个房间放路由器所带来的满意度的提升。(totalPoint[i][0]=totalPoint[0][j]===0)

    代码如下:

    public class WR {
        
        public static int findMaxPoint( int N, int M, int[] roomPoint, int[][] doors )
        {
            int[][] totalPoint = new int[ M+1 ][ N+1 ];
            Set< Integer >[][] roomWiFi = new HashSet[M+1][N+1];
            for( int i = 0; i <= M; i++ ) //M路由器数
            {
                for( int j = 0; j <= N; j++ ) //N房间数
                {
                    roomWiFi[i][j] = new HashSet< Integer >(); 
                    //roomWiFi[i][j]表示前j个房间放入了i个路由器的最高满意度方案中,都有哪些房间已经被WiFi覆盖。
                }        
            }
            for( int m = 1; m <= M; m++ ) //M路由器数
            {
                // totalPoint[ m ][ n ] 表示前n个房间放入了m个路由器的最优满意度分数
                //求出当第n个房间放入路由器后(前n-1个房间放入了m-1个路由器),
                //    比第n个房间不放路由器(前n-1个房间放入了m-1个路由器),所增加的满意度分数
                for( int n = m; n <= N; n++ )
                {    
                    int gain = 0;
                    if( roomWiFi[m-1][n-1].isEmpty() )
                    {
                        for( int i = 1; i <= N; i++ )
                        {
                            if( doors[n][i] == 1 )
                            {
                                gain += roomPoint[i];
                            }                        
                        }
                    }
                    else
                    {
                        for( int hasWiFi : roomWiFi[m-1][n-1] )
                        {
                            for( int i = 1; i <= N; i++ )
                            {
                                if( (doors[hasWiFi][i] == 0) && (doors[n][i] == 1 ) )
                                {
                                    gain += roomPoint[i];
                                }                        
                            }
                        }
                    }
    
                    if( totalPoint[ m ][ n-1 ]  < totalPoint[ m-1 ][n-1] + gain )
                    {
                        totalPoint[ m ][ n ] = totalPoint[ m-1 ][n-1] + gain;
                        roomWiFi[m][n].addAll( roomWiFi[m-1][n-1] );
                        roomWiFi[m][n].add( n );
                    }
                    else
                    {    
                        totalPoint[ m ][ n ] = totalPoint[ m ][ n-1 ] ;
                        roomWiFi[m ][n ].addAll( roomWiFi[m] [n-1] );
                    }                
                }
            }
    //        System.out.println( totalPoint[M][N] );
            return totalPoint[M][N];
    
        }
    
        public static void main(String[] args) {
            int M, N;
            Scanner sc = new Scanner( System.in );
            String line = sc.nextLine();
            N = Integer.parseInt( line.split(" ")[0] );
            M = Integer.parseInt( line.split(" ")[1] );
            int[] roomPoint = new int[N+1];
            int[][] doors = new int[ N+1 ][N+1];
            
            line = sc.nextLine();
            for( int i = 1; i <= N; i++ )
            {            
                int a = Integer.parseInt( line.split(" ")[i-1] );
                roomPoint[i] = a;
            }
            for( int i = 1; i <= N-1; i++ )
            {
                line = sc.nextLine();
                int a = Integer.parseInt( line.split(" ")[0] );
                int b = Integer.parseInt( line.split(" ")[1] );
                doors[a][b] = 1;
                doors[b][a] = 1;
                doors[a][a] = 1;
                doors[b][b] = 1;
            }
            int s = findMaxPoint( N, M, roomPoint, doors );
            System.out.println( s );
        }
    }

    --------------------------------------------------------------------------------------------------------------------------------------------------------------

    题目来源:作业 凸多边形最优三角形划分  http://www.cnblogs.com/Jason-Damon/p/3298172.html

    代码如下:

    cpt.c:
    #include <stdio.h>
    #include "cpt.h"
    
    
    int main()
    {
        int i,j;
        double a_k=0.0;
        time = 0;
        read_from_file( "test_10.txt");
        init_weight();
        set_array_zero( 0, vertex_num, min_w );
        a_k = min_weight( 1, vertex_num-1 );
        printf( "Min cost: %lf
    ",  a_k );
        print_out( 1, vertex_num-1, s );
        
        read_from_file( "test_30.txt");
        init_weight();
        set_array_zero( 0, vertex_num, min_w );
        //a_k = min_weight( 1, vertex_num-1 );
        a_k = min_weight_recursion( 1, vertex_num-1  );
        printf( "Min cost: %lf
    ",  a_k );
        print_out( 1, vertex_num-1, s );
        getchar();
        
        return 0;
    }
    
    func.c:
    #include <stdio.h>
    #include <stdlib.h> //atof
    #include <math.h>
    #include "cpt.h"
    
    void set_array_zero( int i, int j, double a[][VERTEX_MAXNUM])
    {
        int m, n;
        for( m = i; m < j; m++ )
        {
            for( n = i; n < j; n++ )
            {
                a[m][n] = 0.0;
            }
        }
    }
    void read_from_file( char *file )
    {
        char str[100];
        char *p;
        int i;
        FILE* f = fopen( file, "r" );
        if( f == NULL )
        {
            printf( "Open file error
    " );
            exit( 1 );
        }
        /*文件示例:

    n=30

    (40.000,80.000)

    (47.495,79.291)

    (57.031,76.193)

    (63.511,72.361)

    (73.773,61.433)

    ...*/   

    //文件第一行 顶点数 
        fgets( str, 100, f );
        p = strchr( str, '=');
        vertex_num = atoi( p+1 );
        //sscanf( str, "n=%d", &vertex_num );
        //fscanf( f, "n=%d", &vertex_num );
        printf( "vertex_num:%d
    ", vertex_num);
        /*
        fgets( str, 100, f );
        printf( "%s", str);
        fgets( str, 100, f );
        printf( "%s", str);
        */
        //坐标,初始化coor数组 
        for( i = 0; (i < vertex_num) && (fgets( str, 100, f )!=NULL); i++ )
        {
            p = strtok( str, "(, )
    " );
            while( p == NULL )
            {
                fgets( str, 100, f );
                p = strtok( str, "(, )
    " );
            }    
            //printf( "%s,,", p);
            coor[i].x = atof( p );
            p = strtok( NULL, "( , )]r
    " );
            //printf( "%s
    ", p);
            coor[i].y = atof( p );
            //printf("coor[%d]x: %f,coor[%d]y: %f
    ", i,coor[i].x,i,coor[i].y);
        }
        fclose( f );
    }
    
    //计算两点距离
    double calculate_distance( double x1, double y1, double x2, double y2) 
    {
        return sqrt( ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 ) );
    }
    
    //初始化邻接矩阵
    void init_weight()
    {
        
        int i, j;
        for( i = 0; i < vertex_num; i++ )
        {
            for( j = i; j < vertex_num; j++)
            {
                weight[i][j] = calculate_distance( coor[i].x, coor[i].y, coor[j].x, coor[j].y );
                //printf( "%f ", weight[i][j]);
            }
            //printf( "
    ");
        }
    } 
    
    
    double min_weight( int i, int j )
    {
        set_array_zero( 0, vertex_num, min_w );
        int r, begin, end, k;
        double min = 1000000.0, ret;
        for( r = 2; r < vertex_num; r++ ) //r为子问题规模
        {
            for( begin = 1; begin < vertex_num-r+1; begin++ )
            {
                end = begin + r - 1;
                min = 1000000.0;
                for( k = begin; k < end; k++ )
                {
              // min_w[i][j]代表从顶点i-1到j的最优三角划分后的权值总和 ret
    = min_w[begin][k] + min_w[k+1][end] + weight[begin-1][k] + weight[k][end] + weight[begin-1][end]; if( ret < min ) { min = ret; s[begin][end] = k; } } min_w[begin][end] = min; } } return min_w[1][vertex_num-1]; } //递归实现 double min_weight_recursion( int i, int j ) { set_array_zero( 0, vertex_num, min_w ); int k, flag; double ret = 10000000.0; double a, f1, f2; if( i == j ) //i-1, j 两个点 { //printf( "1 "); return 0.0; } for( k = i; k < j; k++ ) { //判断已经存储好的值 if( min_w[i][k] != 0.0 ) f1 = min_w[i][k]; else f1 = min_weight( i, k ); if( min_w[k+1][j] != 0.0 ) f2 = min_w[k+1][j]; else f2 = min_weight( k+1, j ); //a = min_weight( i, k ) + min_weight( k+1, j ) + weight[i-1][k] + weight[k][j] + weight[i-1][j]; a = f1 + f2 + weight[i-1][k] + weight[k][j] + weight[i-1][j]; if( ret > a ) { ret = a; flag = k; } } s[i][j] = flag; min_w[i][j] = ret; //printf( "~~~~~~~%d~ %d~ %d~ %lf~ time:%d ", i-1, flag, j, ret, time++); return ret; } void print_out( int i, int j, int s[][VERTEX_MAXNUM] ) { if( i == j) { return; } int k = s[i][j]; printf( "V%d V%d V%d ", i-1, k, j ); print_out( i, k, s); print_out( k+1, j, s ); } cpt.h: #ifndef _CPT_H #define _CPT_H #define VERTEX_MAXNUM 100 typedef struct coordinate { double x; double y; } Coordinate; // 顶点坐标 Coordinate coor[ VERTEX_MAXNUM ]; //邻接矩阵 上三角 double weight[ VERTEX_MAXNUM ][ VERTEX_MAXNUM ]; //实际顶点数 int vertex_num; //最重要的两个数组,s[i][j]:点i-1 和 j 和这个值k之间有最小权 //min_w[i][j] :点i-1....... j 的最小权值 int s[VERTEX_MAXNUM][VERTEX_MAXNUM]; double min_w[VERTEX_MAXNUM][VERTEX_MAXNUM]; //如果不加函数声明,输出返回值有错 void read_from_file( char *file ); double calculate_distance( double x1, double y1, double x2, double y2); void init_weight(); void print_out( int i, int j, int s[][VERTEX_MAXNUM] ); double min_weight( int i, int j ); void set_array_zero( int i, int j, double a[][VERTEX_MAXNUM]); double min_weight_recursion( int i, int j ); int time; #endif
  • 相关阅读:
    数组
    2022杭电多校部分好题题解(更新至Day 10)
    js入门
    JS数据类型转换
    python赚钱小秘籍每日打新提醒
    jenkins+github+python执行测试用例
    python网络编程socket基础
    Dockerfile介绍与实操
    Docker部署jenkins详细过程
    Faker生成范围内的随机时间格式
  • 原文地址:https://www.cnblogs.com/wangzhiyi/p/6575423.html
Copyright © 2020-2023  润新知