动态规划(dp)入门解题报告

来源:互联网 发布:制作地图软件 编辑:程序博客网 时间:2024/06/05 09:13
基本思想与策略:

    基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。

    由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。



状态抓换方程:

         dp[i][j] = a[i][j] + max(dp[i+1][j], dp[i+1][j+1]);  //dp[i][j]表示从(i,j)位置开始走的最大和

代码:


#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<time.h>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<limits.h>#include<map>//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff//INT_MAX#define inf 0x3f3f3f3f    //int范围内可靠的无穷大#define FOR(i,a) for((i)=0;i<(a);(i)++)                //[i,a);#define MEM(a) (memset((a),0,sizeof(a)))#define sfs(a) scanf("%s",a)#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define pf(a) printf("%d\n",a)#define pfI(a) printf("%I64d\n",a)#define pfs(a) printf("%s\n",a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)#define for1(i,a,b) for(int i=(a);i<b;i++)#define for2(i,a,b) for(int i=(a);i<=b;i++)#define for3(i,a,b)for(int i=(b);i>=a;i--)#define MEM1(a) memset(a,0,sizeof(a))#define MEM2(a) memset(a,-1,sizeof(a))#define LL __int64const double PI = acos(-1.0);template<class T> T gcd(T a, T b) {return b ? gcd(b, a % b) : a;}template<class T> T lcm(T a, T b) {return a / gcd(a, b) * b;}template<class T> inline T Min(T a, T b) {return a < b ? a : b;}template<class T> inline T Max(T a, T b) {return a > b ? a : b;}using namespace std;int n, m;#define N 100int a[N][N];int dp[N][N];void Into(){sf(n);memset(dp,-1,sizeof(dp));for(int i = 1; i <= n; i++)for(int j = 1; j <= i; j++)sf(a[i][j]);}int slove(int i,int j){if(dp[i][j] >= 0)return dp[i][j];                             //记忆化搜索return dp[i][j] = a[i][j] + (i == n ? 0 : Max(slove(i + 1 , j) , slove(i + 1, j + 1)));}int main(){#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);#endifint t;sf(t);while(t--){Into();pf(slove(1,1));}return 0;}

第二题:HDU  2602(01背包问题)

Bone Collector

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 38897    Accepted Submission(s): 16122


Problem Description
Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?

 

Input
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
 

Output
One integer per line representing the maximum of the total value (this number will be less than 231).
 

Sample Input
15 101 2 3 4 55 4 3 2 1
 

Sample Output
14
 

题意:

       第一行是测试组数t,接下来是n,m分别表示物品总数和背包最大载重,接下来的两行分别是价值和重量。

代码:

#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<time.h>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<limits.h>#include<map>//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff//INT_MAX#define inf 0x3f3f3f3f    //int范围内可靠的无穷大#define FOR(i,a) for((i)=0;i<(a);(i)++)//[i,a);#define MEM(a) (memset((a),0,sizeof(a)))#define sfs(a) scanf("%s",a)#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define pf(a) printf("%d\n",a)#define pfI(a) printf("%I64d\n",a)#define pfs(a) printf("%s\n",a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)#define for1(i,a,b) for(int i=(a);i<b;i++)#define for2(i,a,b) for(int i=(a);i<=b;i++)#define for3(i,a,b)for(int i=(b);i>=a;i--)#define MEM1(a) memset(a,0,sizeof(a))#define MEM2(a) memset(a,-1,sizeof(a))#define LL __int64const double PI = acos(-1.0);template<class T> T gcd(T a, T b) {return b ? gcd(b, a % b) : a;}template<class T> T lcm(T a, T b) {return a / gcd(a, b) * b;}template<class T> inline T Min(T a, T b) {return a < b ? a : b;}template<class T> inline T Max(T a, T b) {return a > b ? a : b;}using namespace std;int n, m;#define N 1010int value[N];int weight[N];int dp[N][N];void Into(){sfd(n,m);memset(dp,0,sizeof(dp));for(int i = 1; i <= n ; i++)sf(value[i]);for(int i = 1; i <= n; i++)sf(weight[i]);}int slove(){for(int i = 1; i <= n ;i++){                               //i表示第i件物品
for(int j = 0; j <= m; j++){                       //j表示容量if(weight[i] <= j){dp[i][j] = Max(dp[i - 1][j - weight[i]] + value[i], dp[i-1][j]);          //dp[i][j]表示装入前i个物体在j体积下的最大价值}elsedp[i][j] = dp[i-1][j];}}}int main(){#ifndef ONLINE_JUDGE//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);#endifint t;sf(t);while(t--){Into();slove();                      //核心步骤pf(dp[n][m]);}return 0;}

还有一道题是易彰彪出的捡死鱼问题:

yzb的鱼

时间限制(C/C++):3000MS/6000MS          运行内存限制:65536KByte
总提交:61            测试通过:13

描述

有一天yzb去澳大利亚,忽然天上掉下鱼。
说来yzb的人品实在是太好了,鱼别处都不掉,就掉落在他身旁的10米内。yzb马上找来鱼筐去接,而掉在地上的鱼yzb是不会要的。 
但由于yzb运动基因不发达,每秒种只有在移动不超过一米的范围内接住坠落的鱼。 
为了使问题简化,假设在接下来的一段时间里,鱼都掉落在0-10这11个位置。
开始时yzb站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的鱼。问yzb最多可能接到多少条鱼?

输入

输入数据有多组。每组数据的第一行为以正整数n(0<n<100000),表示有n条鱼掉在这条小径上。
在结下来的n行中,每行有两个整数x,T(0<T<100000),表示在第T秒有一条鱼掉在x点上。
同一秒钟在同一点上可能掉下多个鱼。n=0时输入结束。

输出

每一组输入数据对应一行输出。输出一个整数m,表示yzb最多可能接到m条鱼。

样例输入

6
5 1
4 1
6 1
7 2
7 2
8 3
0

样例输出

4


分析:


代码:

递归:像我这样的低智商玩家一开始只能想到这个。。。。

#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<time.h>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<limits.h>#include<map>//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff//INT_MAX#define inf 0x3f3f3f3f    //int范围内可靠的无穷大#define FOR(i,a) for((i)=0;i<(a);(i)++)//[i,a);#define MEM(a) (memset((a),0,sizeof(a)))#define sfs(a) scanf("%s",a)#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define pf(a) printf("%d\n",a)#define pfI(a) printf("%I64d\n",a)#define pfs(a) printf("%s\n",a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)#define for1(i,a,b) for(int i=(a);i<b;i++)#define for2(i,a,b) for(int i=(a);i<=b;i++)#define for3(i,a,b)for(int i=(b);i>=a;i--)#define MEM1(a) memset(a,0,sizeof(a))#define MEM2(a) memset(a,-1,sizeof(a))#define LL __int64const double PI = acos(-1.0);template<class T> T gcd(T a, T b) {return b ? gcd(b, a % b) : a;}template<class T> T lcm(T a, T b) {return a / gcd(a, b) * b;}template<class T> inline T Min(T a, T b) {return a < b ? a : b;}template<class T> inline T Max(T a, T b) {return a > b ? a : b;}using namespace std;int n, m ,Tm;#define N 100010int a[15][N];int dp[15][N];int Maxt(int a,int b,int c){if(a>b){if(a>c)return a;return c;}else if(b>c)return b;return c;}void Into(){Tm = -inf;memset(a,0,sizeof a);memset(dp,-1,sizeof dp);int p,t;for(int i = 0; i < n; i++){sfd(p,t);a[p][t]++;Tm = Tm > t ? Tm : t;}}int slove(int i,int j){if(dp[i][j] >= 0)return dp[i][j];if(j == Tm)return dp[i][j] = a[i][j];else if(i == 10)return dp[i][j] = a[i][j] + Max(slove( i ,j + 1),slove(i - 1, j + 1));else if(!i){return dp[i][j] = a[i][j] + Max(slove(i + 1,j + 1),slove(i , j + 1));}elsereturn dp[i][j] = a[i][j] + Maxt(slove(i - 1 ,j + 1),slove(i, j + 1),slove(i + 1,j + 1));}int main(){#ifndef ONLINE_JUDGE//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);#endifwhile(sf(n)!=EOF && n){Into();pf(slove(5,0));}return 0;}
循环:别人优化了一下,自己写了一遍
#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<time.h>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<limits.h>#include<map>//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff//INT_MAX#define inf 0x3f3f3f3f    //int范围内可靠的无穷大#define FOR(i,a) for((i)=0;i<(a);(i)++)//[i,a);#define MEM(a) (memset((a),0,sizeof(a)))#define sfs(a) scanf("%s",a)#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define pf(a) printf("%d\n",a)#define pfI(a) printf("%I64d\n",a)#define pfs(a) printf("%s\n",a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)#define for1(i,a,b) for(int i=(a);i<b;i++)#define for2(i,a,b) for(int i=(a);i<=b;i++)#define for3(i,a,b)for(int i=(b);i>=a;i--)#define MEM1(a) memset(a,0,sizeof(a))#define MEM2(a) memset(a,-1,sizeof(a))#define LL __int64const double PI = acos(-1.0);template<class T> T gcd(T a, T b) {return b ? gcd(b, a % b) : a;}template<class T> T lcm(T a, T b) {return a / gcd(a, b) * b;}template<class T> inline T Min(T a, T b) {return a < b ? a : b;}template<class T> inline T Max(T a, T b) {return a > b ? a : b;}using namespace std;template<class T>T Mint(T a,T b,T c){if(a>b){if(c>b)return b;return c;}if(c>a)return a;return c;}template<class T>T Maxt(T a, T b, T c){if(a>b){if(c>a)return c;return a;}else if(c > b)return c;return b;}int n, m ;#define N 100010int a[N][15];                     // a[i][j] j位置,i时刻能得到的鱼int dp[N][15];                    // dp[i][j] j位置,i时间后所获得的最大值void slove(int Tm){for(int i = Tm; i >= 0; i--){for(int j = 0; j <= 10 ; j++){if(i == Tm){dp[i][j] = a[i][j];}else if(!j){dp[i][j] = a[i][j] + Max(dp[i+1][j],dp[i+1][j+1]);}else if(j == 10){dp[i][j] = a[i][j] + Max(dp[i+1][j],dp[i+1][j-1]);}else{dp[i][j] = a[i][j] + Maxt(dp[i+1][j-1],dp[i+1][j],dp[i+1][j+1]);}}}pf(dp[0][5]);}void Into(){int t;int position,time;while(sf(t)!=EOF && t){int Tm = -inf;memset(dp,0,sizeof(dp));memset(a,0,sizeof(a));while(t--){sfd(position,time);a[time][position]++;Tm = Tm > time ? Tm : time;}slove(Tm);}}int main(){#ifndef ONLINE_JUDGEfreopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);#endifInto();return 0;}


用循环比用递归快了很多了。

最后一道题,王教授出在oj上的题。

最长不降奇偶交替子列

时间限制(C/C++):1000MS/3000MS          运行内存限制:65536KByte
总提交:227            测试通过:38

描述

一个序列中选择其中的若干个,保持以前顺序生成的新的序列称为原序列的子列,如果子列中每相邻两个元素的奇偶性交替出现,则称这个子列为奇偶交替子列。你的任务是:对于给定的序列, 计算出其最长单调不降奇偶交替子列的长度。

输入

输入的第1行是一个整数n,在[1, 20]之间,表示测试用例的数量。对于每一个测试用例, 第一行是一个整数mi,表示该测试用例序列中数据的数量,在[2, 200]中。后面紧跟mi行,每一行是该序列的一个数据,每个数据在区间[-10000, 10000]之中。

输出

对于每个测试用例,输出一行,只包含一个整数,表示相应测试用例最长不降奇偶交替子列的长度。

样例输入

5
4
-10
-5
-8
-2
8
9
-7
-9
-3
-13
-15
7
7
1
-6
6
-17
-15
-8
-2
-7
-8
2
-7
0

样例输出

3
1
1
3
2

分析:想了想自己模拟了一遍画出来大概是棵树的结构,至于是什么树我也不知道,还没学到。


  字好丑!

代码:

#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<time.h>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<limits.h>#include<map>//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff//INT_MAX#define inf 0x3f3f3f3f    //int范围内可靠的无穷大#define FOR(i,a) for((i)=0;i<(a);(i)++)//[i,a);#define MEM(a) (memset((a),0,sizeof(a)))#define sfs(a) scanf("%s",a)#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define pf(a) printf("%d\n",a)#define pfI(a) printf("%I64d\n",a)#define pfs(a) printf("%s\n",a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)#define for1(i,a,b) for(int i=(a);i<b;i++)#define for2(i,a,b) for(int i=(a);i<=b;i++)#define for3(i,a,b)for(int i=(b);i>=a;i--)#define MEM1(a) memset(a,0,sizeof(a))#define MEM2(a) memset(a,-1,sizeof(a))#define LL __int64const double PI = acos(-1.0);template<class T> T gcd(T a, T b) {return b ? gcd(b, a % b) : a;}template<class T> T lcm(T a, T b) {return a / gcd(a, b) * b;}template<class T> inline T Min(T a, T b) {return a < b ? a : b;}template<class T> inline T Max(T a, T b) {return a > b ? a : b;}using namespace std;template<class T>T Mint(T a,T b,T c){if(a>b){if(c>b)return b;return c;}if(c>a)return a;return c;}template<class T>T Maxt(T a, T b, T c){if(a>b){if(c>a)return c;return a;}else if(c > b)return c;return b;}int mod(int a){return a % 2 < 0 ? -a % 2 : a % 2;}int n, m ;#define N 210int a[N],dp[N];void slove(){dp[n-1] = 1;for(int i = n - 1; i >= 0; i--){for(int j = i + 1; j < n; j++){if(a[i] < a[j] && mod(a[i]) != mod(a[j])){dp[i] = Max(dp[j] + 1,dp[i]);}else{dp[i] = Max(dp[i],1);}}}int max = 0;for(int i = 0; i < n; i++)max = max < dp[i] ? dp[i] : max;pf(max);//pf(dp[0]);                  //dp[i]的含义是选了第i项之后形成的最长不降奇偶交替子列的最大长度而不是从第i项开始的最长。。。子列长度//putchar(10);}void Into(){sf(m);while(m--){memset(a,0,sizeof(a));memset(dp,0,sizeof(dp));sf(n);for1(i,0,n)sf(a[i]);slove();}}int main(){#ifndef ONLINE_JUDGE//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);#endifInto();return 0;}


然后是一道poj上的题目:

Football
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 3780 Accepted: 1934

Description

Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, …, 2n. In each round of the tournament, all teams still in the tournament are placed in a list in order of increasing index. Then, the first team in the list plays the second team, the third team plays the fourth team, etc. The winners of these matches advance to the next round, and the losers are eliminated. After n rounds, only one team remains undefeated; this team is declared the winner.

Given a matrix P = [pij] such that pij is the probability that team i will beat team j in a match determine which team is most likely to win the tournament.

Input

The input test file will contain multiple test cases. Each test case will begin with a single line containing n (1 ≤ n ≤ 7). The next 2n lines each contain 2n values; here, the jth value on the ith line represents pij. The matrix P will satisfy the constraints that pij = 1.0 − pji for all i ≠ j, and pii = 0.0 for all i. The end-of-file is denoted by a single line containing the number −1. Note that each of the matrix entries in this problem is given as a floating-point value. To avoid precision problems, make sure that you use either the double data type instead of float.

Output

The output file should contain a single line for each test case indicating the number of the team most likely to win. To prevent floating-point precision issues, it is guaranteed that the difference in win probability for the top two teams will be at least 0.01.

Sample Input

20.0 0.1 0.2 0.30.9 0.0 0.4 0.50.8 0.6 0.0 0.60.7 0.5 0.4 0.0-1

Sample Output

2

Hint

In the test case above, teams 1 and 2 and teams 3 and 4 play against each other in the first round; the winners of each match then play to determine the winner of the tournament. The probability that team 2 wins the tournament in this case is:

P(2 wins) = P(2 beats 1)P(3 beats 4)P(2 beats 3) + P(2 beats 1)P(4 beats 3)P(2 beats 4)
p21p34p23 + p21p43p24
= 0.9 · 0.6 · 0.4 + 0.9 · 0.4 · 0.5 = 0.396.

The next most likely team to win is team 3, with a 0.372 probability of winning the tournament.


分析:


代码:


#include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<algorithm>#include<vector>#include<time.h>#include<queue>#include<stack>#include<iterator>#include<math.h>#include<stdlib.h>#include<map>#include<set>//#define ONLINE_JUDGE#define eps 1e-8#define INF 0x7fffffff                                            //INT_MAX#define inf 0x3f3f3f3f                                            //int??????????????????#define FOR(i,a) for((i)=0;i<(a);(i)++)                            //[i,a);#define MEM(a) (memset((a),0,sizeof(a)))#define sfs(a) scanf("%s",a)#define sf(a) scanf("%d",&a)#define sfI(a) scanf("%I64d",&a)#define pf(a) printf("%d\n",a)#define pfI(a) printf("%I64d\n",a)#define pfs(a) printf("%s\n",a)#define sfd(a,b) scanf("%d%d",&a,&b)#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)#define for1(i,a,b) for(int i=(a);i<b;i++)#define for2(i,a,b) for(int i=(a);i<=b;i++)#define for3(i,a,b)for(int i=(b);i>=a;i--)#define MEM1(a) memset(a,0,sizeof(a))#define MEM2(a) memset(a,-1,sizeof(a))#define LL __int64const double PI = acos(-1.0);template<class T> T gcd(T a, T b) {return b ? gcd(b, a % b) : a;}template<class T> T lcm(T a, T b) {return a / gcd(a, b) * b;}template<class T> inline T Min(T a, T b) {return a < b ? a : b;}template<class T> inline T Max(T a, T b) {return a > b ? a : b;}using namespace std;int  n,m;#define N 130double team[N][N];double dp[N][N];int sum;void Init() {memset(dp, 0, sizeof(dp));sum = 1 << n;for (int i = 1; i <= sum; i++) {for (int j = 1; j <= sum; j++) {scanf("%lf", &team[i][j]);}}}void compute(){for(int i = 1; i <= n; i++){for(int j = 1; j <= sum; j++){if(i == 1){if(j % 2)dp[i][j] = team[j][j + 1];elsedp[i][j] = team[j][j - 1];}else{int flag = ((j - 1) / (1 << (i - 1))) + 1;                                       // 当前队伍的组for(int k = 1; k <= sum; k++){int temp_flag = ((k - 1) / (1 << (i - 1))) + 1;<span style="white-space:pre"></span> // 要比较的队伍的组if(flag % 2 && temp_flag == flag + 1){dp[i][j] += (dp[i - 1][k] * dp[i - 1][j] * team[j][k]);}if(flag % 2 == 0 && temp_flag == flag - 1){dp[i][j] += (dp[i - 1][k] * dp[i - 1][j] * team[j][k]);}}}}}}int main() {#ifndef ONLINE_JUDGE//freopen("in.txt","r",stdin);//freopen("out.txt","w",stdout);#endifwhile (sf(n) != EOF && n != -1) {Init();compute();int num = 0; double p = -1.0;for(int i = 1; i <= sum; i++){if(dp[n][i] > p){p = dp[n][i];num = i;}}pf(num);}return 0;}

0 0
原创粉丝点击