动态规划

在做笔试题时,碰到了几个不会做的题,其中大部分是关于动态规划的。01背包问题,硬币博弈问题。。。


任何数学递归公式都可以直接翻译成递归算法。但常常编译器不能正确对待递归算法,导致低效的算法。我们将递归算法重新写成非递归算法,让后者把那些子问题的答案系统地记录在一个表内。利用这种方法的一种技巧叫做动态规划(dynamic programming)


动态规划一般可分为线性动规,区域动规,树形动规,背包动规四类。

举例:

线性动规:拦截导弹,合唱队形,挖地雷,建学校,剑客决斗等;

区域动规:石子合并, 加分二叉树,统计单词个数,炮兵布阵等;

树形动规:贪吃的九头龙,二分查找树,聚会的欢乐,数字三角形等;

背包问题:01背包问题,完全背包问题,分组背包问题,二维背包,装箱问题,挤牛奶(同济ACM第1132题)等;

应用实例:

最短路径问题 ,项目管理,网络流优化等;

POJ动态规划题目列表:

容易:
  1018,1050,1083,1088,1125,1143,1157,1163,1178,1179,1189,1191,1208,1276,1322,1414,1456,1458,1609,1644,1664,1690,1699,1740,1742,1887,1926,1936,1952,1953,1958,1959,1962,1975,1989,2018,2029,2039,2063,2081,2082,2181,2184,2192,2231,2279,2329,2336,2346,2353,2355,2356,2385,2392,2424。

不易:
  1019,1037,1080,1112,1141,1170,1192,1239,1655,1695,1707,1733(区间减法加并查集),1737,1837,1850,1920(加强版汉罗塔),1934(全部最长公共子序列),1964(最大矩形面积,O(n*m)算法),2138,2151,2161,2178。

推荐:
  1015,1635,1636,1671,1682,1692,1704,1717,1722,1726,1732,1770,1821,1853,1949,2019,2127,2176,2228,2287,2342,2374,2378,2384,2411。[1] 

解决0-1背包问题时使用动态规划的实现(c++)

#include <stdio.h>

typedef struct Object{

int weight;

int value; // float rate;

}

Object;

Object * array; //用来存储物体信息的数组

int num; //物体的个数

int container; //背包的容量

int ** dynamic_table; //存储动态规划表

bool * used_table; //存储物品的使用情况

//ouput the table of dynamic programming, it's for detection

void print_dynamic_table(){

printf("动态规划表如下所示:\n");

/* for(int j=0; j<=container; j++) printf("%d ",j); printf("\n");*/

for(int i=1; i<=num; i++) {

for(int j=0; j<=container; j++)

printf("%d ",dynamic_table[i][j]);

printf("\n");

}

}

//打印动态规划表

void print_array(){

for(int i=1; i<=num; i++)

printf("第%d个物品的重量和权重:%d %d\n",i,array[i].weight,array[i].value);

}

//打印输入的物品情况//插入排序,按rate=value/weight由小到大排//动态规划考虑了所有情况,所以可以不用排序

/*void sort_by_rate(){

for(int i=2; i<=num; i++) {

Object temp=array[i];

for(int j=i-1; j>=1; j--)

if(array[j].rate>temp.rate)

array[j+1]=array[j];

else break;

array[j+1]=temp;

}}*/

void print_used_object(){

printf("所使用的物品如下所示:\n");

for(int i=1; i<=num; i++)

if(used_table[i]==1)

printf("%d-%d\n", array[i].weight, array[i].value);

}

//打印物品的使用情况

/* 做测试时使用

void print_used_table(bool * used_table){

printf("used table as follows:\n");

for(int i=1; i<=num; i++)

printf("object %d is %d", i, used_table[i]);

}*/

void init_problem(){

printf("输入背包的容量:\n");

scanf("%d", &container);

printf("输入物品的个数:\n");

scanf("%d", &num);

array=new Object[num+1];

printf("输入物品的重量和价值, 格式如:4-15\n");

for(int i=1; i<=num; i++) {

char c;

scanf("%d%c%d", &array[i].weight, &c, &array[i].value);

// array[i].rate=array[i].value/array[i].weight;

}

print_array();

}

//对物体的使用情况进行回查

void trace_back(){

int weight=container;

used_table=new bool[num+1];

for(int i=1; i<=num; i++) used_table[i]=0;

//initalize the used_table to be non-used

for(int j=1; j<num; j++) {

//说明物品j被使用

if(dynamic_table[j][weight]!=dynamic_table[j+1][weight]) {

weight-=array[j].weight;

used_table[j]=1;

}

// print_used_table(used_table);

}

//检测第num个物品是否被使用

if(weight>=array[num].weight)

used_table[num]=1;

}

void dynamic_programming(){

dynamic_table=new int * [num+1];

for(int k=1; k<=num; k++)

dynamic_table[k]=new int[container+1];

//dynamic_programming table

//为二维动态规划表分配内存

for(int m=1; m<num; m++)

for(int n=0; n<=container; n++)

dynamic_table[m][n]=0;

int temp_weight=array[num].weight;

for(int i=0; i<=container; i++)

dynamic_table[num][i]=i<temp_weight?0:array[num].value;

//初始化动态规划表

for(int j=num-1; j>=1; j--) {

temp_weight=array[j].weight;

int temp_value=array[j].value;

for(int k=0; k<=container; k++)

if(k>=temp_weight && dynamic_table[j+1][k] < dynamic_table[j+1][k-temp_weight]+temp_value)

dynamic_table[j][k]=dynamic_table[j+1][k-temp_weight]+temp_value;

else dynamic_table[j][k]=dynamic_table[j+1][k];

}//构建动态规划表

print_dynamic_table();//打印动态规划表

}

void main(){

init_problem();

dynamic_programming();

trace_back();

print_used_object();

}


你可能感兴趣的:(动态规划)