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

题目来源: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[]; // 满足最大的n
int sumOfFre[];
int dp[][]; // should output dp[1][n] int main(int argc, char** argv) {
//读取数据
int n;
cin >> n; sumOfFre[] = ;
frequence[] = ; for( int i = ; i <= n; i++ )
{
cin >> frequence[i]; sumOfFre[i] = sumOfFre[i-] + frequence[i]; dp[i][i] = frequence[i]; //下标从 1 ~ n
//dp[i][i] = 0; //下标从 1 ~ n
} for( int step = ; 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 = ; i < n-step+; i++ )
{
int j = i + step;
dp[i][j] = MAX;
for( int k = i; k < j; k++ )
{
if( k != i && (k+) != j )
{
dp[i][j] = min( dp[i][k] + dp[k+][j] + sumOfFre[j] - sumOfFre[i-], dp[i][j] );
// cout << "---1 i: " << i << " k: " << k << " j: " << j << " dp[i][j]: " << dp[i][j] << endl;
}
else if ( k == i && (k+) != j )
{
dp[i][j] = min( dp[i][k] + dp[k+][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+) == j )
{
dp[i][j] = min( dp[i][k] + dp[k+][j] + sumOfFre[k] - sumOfFre[i-], dp[i][j] );
// cout << "---3 i: " << i << " k: " << k << " j: " << j << " dp[i][j]: " << dp[i][j] << endl;
}
else if ( k == i && (k+) == j )
{
dp[i][j] = min( dp[i][k] + dp[k+][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[][n] << endl; return ;
}

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

题目来源:一道笔试题 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 = ;
read_from_file( "test_10.txt");
init_weight();
set_array_zero( , vertex_num, min_w );
a_k = min_weight( , vertex_num- );
printf( "Min cost: %lf\n", a_k );
print_out( , vertex_num-, s ); read_from_file( "test_30.txt");
init_weight();
set_array_zero( , vertex_num, min_w );
//a_k = min_weight( 1, vertex_num-1 );
a_k = min_weight_recursion( , vertex_num- );
printf( "Min cost: %lf\n", a_k );
print_out( , vertex_num-, s );
getchar(); return ;
} 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[];
char *p;
int i;
FILE* f = fopen( file, "r" );
if( f == NULL )
{
printf( "Open file error\n" );
exit( );
}
/*文件示例: n=30

(40.000,80.000)

(47.495,79.291)

(57.031,76.193)

(63.511,72.361)

(73.773,61.433)

...*/   

//文件第一行 顶点数
fgets( str, , f );
p = strchr( str, '=');
vertex_num = atoi( p+ );
//sscanf( str, "n=%d", &vertex_num );
//fscanf( f, "n=%d", &vertex_num );
printf( "vertex_num:%d\n", vertex_num);
/*
fgets( str, 100, f );
printf( "%s", str);
fgets( str, 100, f );
printf( "%s", str);
*/
//坐标,初始化coor数组
for( i = ; (i < vertex_num) && (fgets( str, , f )!=NULL); i++ )
{
p = strtok( str, "(, )\r\n" );
while( p == NULL )
{
fgets( str, , f );
p = strtok( str, "(, )\r\n" );
}
//printf( "%s,,", p);
coor[i].x = atof( p );
p = strtok( NULL, "( , )]r\n" );
//printf( "%s\n", p);
coor[i].y = atof( p );
//printf("coor[%d]x: %f,coor[%d]y: %f\n", 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 = ; 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( "\n");
}
} double min_weight( int i, int j )
{
set_array_zero( , vertex_num, min_w );
int r, begin, end, k;
double min = 1000000.0, ret;
for( r = ; r < vertex_num; r++ ) //r为子问题规模
{
for( begin = ; begin < vertex_num-r+; begin++ )
{
end = begin + r - ;
min = 1000000.0;
for( k = begin; k < end; k++ )
{
          // min_w[i][j]代表从顶点i-1到j的最优三角划分后的权值总和
ret = min_w[begin][k] + min_w[k+][end] + weight[begin-][k] + weight[k][end] + weight[begin-][end];
if( ret < min )
{
min = ret;
s[begin][end] = k;
}
}
min_w[begin][end] = min;
}
}
return min_w[][vertex_num-]; }
//递归实现
double min_weight_recursion( int i, int j )
{
set_array_zero( , vertex_num, min_w );
int k, flag;
double ret = 10000000.0;
double a, f1, f2;
if( i == j ) //i-1, j 两个点
{
//printf( "1\n");
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+][j] != 0.0 )
f2 = min_w[k+][j];
else
f2 = min_weight( k+, 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-][k] + weight[k][j] + weight[i-][j];
if( ret > a )
{
ret = a;
flag = k;
}
}
s[i][j] = flag;
min_w[i][j] = ret;
//printf( "~~~~~~~%d~ %d~ %d~ %lf~ time:%d\n", 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 \n", i-, k, j );
print_out( i, k, s);
print_out( k+, 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

动态规划:压缩编码;WirelessRouters;的更多相关文章

  1. CCF(压缩编码):动态规划+平行四边形优化

    压缩编码 201612-4 一开始看这题还以为是哈夫曼编码的题目,结果是哈夫曼题目的变形. 哈夫曼编码是每次合并任意两堆石子,而这里的题目是合并相邻的两堆石子,而且这里的合并花费是合并两堆石子加上所有 ...

  2. 增强学习(三)----- MDP的动态规划解法

    上一篇我们已经说到了,增强学习的目的就是求解马尔可夫决策过程(MDP)的最优策略,使其在任意初始状态下,都能获得最大的Vπ值.(本文不考虑非马尔可夫环境和不完全可观测马尔可夫决策过程(POMDP)中的 ...

  3. 简单动态规划-LeetCode198

    题目:House Robber You are a professional robber planning to rob houses along a street. Each house has ...

  4. 动态规划 Dynamic Programming

    March 26, 2013 作者:Hawstein 出处:http://hawstein.com/posts/dp-novice-to-advanced.html 声明:本文采用以下协议进行授权: ...

  5. 动态规划之最长公共子序列(LCS)

    转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...

  6. C#动态规划查找两个字符串最大子串

     //动态规划查找两个字符串最大子串         public static string lcs(string word1, string word2)         {            ...

  7. C#递归、动态规划计算斐波那契数列

    //递归         public static long recurFib(int num)         {             if (num < 2)              ...

  8. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  9. 【BZOJ1700】[Usaco2007 Jan]Problem Solving 解题 动态规划

    [BZOJ1700][Usaco2007 Jan]Problem Solving 解题 Description 过去的日子里,农夫John的牛没有任何题目. 可是现在他们有题目,有很多的题目. 精确地 ...

随机推荐

  1. python学习笔记之函数的参数

    函数的参数有位置参数和关键字参数,位置参数一定要在关键字参数的前面,位置参数的优先级是高于关键字参数的,否则会报错 def my_abs(a,b): print(a) print(b) my_abs( ...

  2. mac+windows下从git上拉取项目及运行

    一.Mac下从git拉取项目 1. 拉项目 打开终端,先进入想放置项目的目录.假设进入workfile目录,输入cd workfile. 进入workfile目录后:输入git clone 链接(gi ...

  3. MongoDB的常规备份策略

    MongoDB的备份其实算是一个基本操作,最近总是有人问起,看来很多人对这里还不太熟悉.为了避免一次又一次地重复解释,特总结成一篇博客供后来者查阅.如有不尽正确之处请指正. 1. 内建方法 1.1 复 ...

  4. css3的2D和3D的转换

    一:2D转换: 通过 CSS3  transform转换,我们能够对元素进行移动.缩放.转动.拉长或拉伸. 2D移动:translate().使用translate()函数,你可以把元素从原来的位置移 ...

  5. 给RabbitMQ发送消息时,设置请求头Header。

    消费者的请求头 生产者设置请求头 由于消费者那里,@Payload是接受的消息体,使用了@Header注解,需要请求头,生产者这边就要设置请求头,然后rabbitTemplate再调用convertA ...

  6. ADO.Net创建数据模型和数据访问类及泛型集合

    数据模型和数据访问类:数据模型: 使用面向对象中的封装特性,将数据表中的行数据组成一个同样结构的对象,来单独使用: 数据访问类: 将某一个表的全部增删改查操作的方法写进去,方便统一管理和调用: 数据模 ...

  7. ABAP 常用函数

    函数名 描述 SD_VBAP_READ_WITH_VBELN 根据销售订单读取表vbap中的信息EDIT_LINES 把READ_TEXT返回的LINES中的行按照TDFORMAT=“*”重新组织VI ...

  8. python scrapy 插入数据库的操作

    需要安装这个 pymysql 写法还是很简单的 # -*- coding: utf-8 -*- # Define your item pipelines here # # Don't forget t ...

  9. 动态代理 JDK动态代理 CGLIB代理

    代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法.实际执行的是被代理类的方法. 而AOP,是通过动态代理实现的. 一.简单来说: JD ...

  10. mybatis 插入返回自增后的id

    //serviceImpl int customerId = customerDao.insertDynamic(customer1); System.out.println("id==== ...