zoukankan      html  css  js  c++  java
  • 动态规划:压缩编码;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
  • 相关阅读:
    ubuntu远程windows桌面
    spring boot 给返回值加状态 BaseData
    spring boot 拦截异常 统一处理
    IntelliJ IDEA spring boot 远程Ddbug调试
    IntelliJ IDEA 常用插件
    spring boot 请求地址带有.json 兼容处理
    spring boot 接口返回值去掉为null的字段
    spring boot 集成disconf
    Spring boot 自定义拦截器
    Linux下安装MySQL
  • 原文地址:https://www.cnblogs.com/wangzhiyi/p/6575423.html
Copyright © 2011-2022 走看看