Dynamic planning summary

—Restoring content begins—

Dynamic programming comes from the divide and conquer method. The solution is recorded to prevent the system from doing repetitive work and wasting time.

Generally, when using dynamic programming to do problems, we should start with the divide-and-conquer method, and further consider whether there are the same sub-problem solutions and whether the solutions are repeated. If so, we can use dynamic programming to solve [Of course, recursive equations still have to be written of】.

The recursive equation of dynamic programming is slightly different from the divide-and-conquer method. The recursion of dynamic programming generally uses two-dimensional arrays to store data [Of course, one-dimensional arrays or even a variable are also useful, but they are all two-dimensional arrays. Simplified version], first we have to figure out the geometric meaning of m[i][j], and then write m[i][j]=…[usually linked to other elements of m], This is the recursive equation of dynamic programming.

Generally writing recursive equations is divided into the following situations

1. Determine the starting point and ending point of the planning, and the planning direction is determined

Example questions:

7-1 Digital triangle (30 minutes)

Given a digital triangle composed of n rows of numbers as shown in the figure below. Try to design an algorithm to calculate a path from the top to the bottom of the triangle (each step can go down the left oblique line or down the right oblique line) to maximize the sum of the numbers that the path passes.

QQ screenshot20170929023616.jpg

Input format:

There are n+1 lines of input:

The first line is the number of lines of the digital triangle n, 1<=n<=100.

The next n rows are the numbers in each row of the number triangle. All numbers are between 0..99.

Output format:

Output the value of the maximum path.

Input example:

A set of input is given here. For example:

5

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

Sample output:

The corresponding output is given here. For example:

30

Generally encountered this problem only If you need to start from the end point, you will find that the path value to the end point can only be m[i-1][j] or m[i-1][j-1] plus your own value. In this way, the problem of reaching the end point will be It is transformed into the value that reaches the second-to-last grid, and so on.

#include

using namespace std;

int main()
{
int n,i,j;
cin
>>n;
int a[101][101];
int d[101][101];
for(i=1;i<101;i++)
{
for(j=1;j<101;j++)
{
a[i][j]
=0;
}
}
for(i=1;i<=n ;i++)
{
for(j=1;j<=i ;j++)
{
cin
>>a[i][j];
}
}

for(j=1;j<=n;j++)
{
d[n][j]
=a[n][j];
}
for(i=n-1;i> =1;i--)
{
for(j=1;j<=n ;j++)
{
if(d[i+1][j] >d[i+1][j+1])
{
d[i][j]
=d[i+1][j]+a[i][j];
}
else
{
d[i][j]
=d[i+1][j+1]+a[i][j];
}
}
}
cout
<1][1< span style="color: #000000;">];
}

Of course, it is also possible to directly overwrite the a array without creating the d array

Conclusion: This kind of direction-oriented question At the end, think about each situation clearly, and then get the maximum and minimum.

Other issues: Tolls for merchants, the problem of finding the minimum operands of sub-segments

2. The direction is uncertain or free, the starting and ending points are determined:

3-2 The problem of renting a yacht (22 points)

The source of the topic: Wang Xiaodong, “Algorithm Design and Analysis”

The Yangtze River Yacht Club has set up n yacht rental stations 1, 2, …, n on the Yangtze River. Tourists can rent yachts at these yacht rental stations and return the yachts at any yacht rental station downstream. The rent between yacht rental station i and yacht rental station j is r(i,j), 1<=i

Input format:

There is a positive integer n (n<=200) in the first line, which means there are n yacht rental stations. The next line 1 to n-1, line i represents the rent from station i to station i+1, station i+2, ..., station n.

Output format:

Output the minimum rent required from yacht rental station 1 to yacht rental station n.

Input example:

A set of input is given here. For example:

3

5 15
7

Sample output:

The corresponding output is given here. For example:

12

This question also starts from the end point to the start point. From i to n, either go directly or pass through Reactor midway stations, and the values ​​of these midway stations can be solved as sub-problems.

Recursive equation: m[i][j] starts from the ith station to j=max(m[i][k]+m[k][j],m[i][j ]) Where k

#include

using namespace std;
int main()
{
int n,i,j,k;
int yangtzeriver[200][200];
cin
>>n;
for(i=0;i)
{
yangtzeriver[i][i]=0;

}
for(i=0;i)
{
for(j=i+1;j)
{
cin>>yangtzeriver[i][j];

}
}
//cout<<"e";
for(i=n-1;i>=0;i--)
{
//cout<<" d";
for(j=i+1;j)
{
//cout<

int mini=min(yangtzeriver[i][j],yangtzeriver[i][j-1]+yangtzeriver[j-1][j]);
for(k=i+1;k)
{
int q=min(yangtzeriver[i][j],yangtzeriver[i][k]+yangtzeriver[k][j]);
//cout<
if(q<mini)
{
mini
=q;
}
}
//cout<
yangtzeriver[i][j]=mini;
}
}
cout
<0
][n-1];

Such as: 3-1, 3-3

3. The direction is determined, the starting and ending points are not free

The general method is Record maximum value

Such as:

3-2 Yacht rental problem (22 points)

The source of the topic: Wang Xiaodong, “Algorithm Design and Analysis”

The Yangtze River Yacht Club has set up n yacht rental stations 1, 2, …, n on the Yangtze River. Tourists can rent yachts at these yacht rental stations and return the yachts at any yacht rental station downstream. The rent between yacht rental station i and yacht rental station j is r(i,j), 1<=i

Input format:

There is a positive integer n (n<=200) in the first line, which means there are n yacht rental stations. The next line 1 to n-1, line i represents the rent from station i to station i+1, station i+2, ..., station n.

Output format:

Output the minimum rent required from yacht rental station 1 to yacht rental station n.

Input example:

A set of input is given here. For example:

3

5 15
7

Sample output:

The corresponding output is given here. For example: 12

 generally encounter this kind of question, don’t Limit thinking to the end. Think of it this way: starting from any number, if the previous pile of numbers <0, 
then the last string with him as the base is itself, otherwise the previous pile of numbers plus this number will get the recursive equation m[j]= max(m[j-1]+num[j],num[j]),
or if num[j]<0,m[j]=num[j],else m[j]=(m [j-1]+num[j])
Code omit reading by yourself
 //Reading


 (Of course, the direct divide-and-conquer method plus a memo is also possible)

4. No one's own Pick such as 0-1 backpack
0-1 backpack: Given a kind of item and a backpack with a capacity of, the weight of the item is, and its value is. The problem of the backpack is how to choose the items to be loaded into the backpack so that it can be loaded The total value of the items in the backpack is the largest. Among them, there are only two options for each item to be loaded into the backpack or not into the backpack.
The representative meaning of a two-dimensional array of such topics will be very strange. For example, in a 0-1 backpack, one number represents the number of items from which to load, and the other number represents the capacity.
After understanding the order of the two-dimensional array, it will be obvious that m[i][j]=max(m[i+1][ji’s value],m[i+1][j])[Premise : Can be loaded (j>the value of i), can not be loaded directly m[i+1][j]]
Then fill in the last line and you can fill in the form up
 

#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity ;j++)
{
if(j1< span style="color: #000000;">])
{
bag[n-1][j]=0;
}
else bag[n-1][j] =percapity[n-1];
}
for(i=n-2;i> =0;i--)
{
for(j=1;j<=capity ;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1< /span>][j];
}
}
cout
<0
][capity];
}


Under normal circumstances, we can get the result of m[i][j] according to the results before the table, usually It is necessary to compare the relationship between i, j and i, j in the recursive formula, so as to get the order of i and j in the for loop of filling the table, so as to find whether i and j increase or increase. Generally, in the recursive formula, i decreases by a larger amount than the original i, otherwise it increases, and j is the same.

7-1 Digital triangle (30 minutes)

>

Given a digital triangle consisting of n rows of numbers, as shown in the figure below. Try to design an algorithm to calculate a path from the top to the bottom of the triangle (each step can go down the left oblique line or down the right oblique line) to maximize the sum of the numbers that the path passes.

QQ screenshot20170929023616.jpg

Input format:

There are n+1 lines of input:

The first line is the number of lines of the digital triangle n, 1<=n<=100.

The next n rows are the numbers in each row of the number triangle. All numbers are between 0..99.

Output format:

Output the value of the maximum path.

Input example:

A set of input is given here. For example:

5

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

Sample output:

The corresponding output is given here. For example:

30

7-1 Digital triangle (30 points)

Given a digital triangle composed of n rows of numbers as shown in the figure below. Try to design an algorithm to calculate a path from the top to the bottom of the triangle (each step can go down the left oblique line or down the right oblique line) to maximize the sum of the numbers that the path passes.

QQ screenshot20170929023616.jpg

Input format:

There are n+1 lines of input:

The first line is the number of lines of the digital triangle n, 1<=n<=100.

The next n rows are the numbers in each row of the number triangle. All numbers are between 0..99.

Output format:

Output the value of the maximum path.

Input example:

A set of input is given here. For example:

5

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

Sample output:

The corresponding output is given here. For example:

30

7-1 Digital triangle (30 minutes)

Given a digital triangle composed of n rows of numbers, as shown in the figure below. Try to design an algorithm to calculate a path from the top to the bottom of the triangle (each step can go down the left oblique line or down the right oblique line) to maximize the sum of the numbers that the path passes.

QQ screenshot20170929023616.jpg

Input format:

There are n+1 lines of input:

The first line is the number of lines of the digital triangle n, 1<=n<=100.

The next n rows are the numbers in each row of the number triangle. All numbers are between 0..99.

Output format:

Output the value of the maximum path.

Input example:

A set of input is given here. For example:

5

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

Sample output:

The corresponding output is given here. For example:

30

7-1 Digital triangle (30 minutes)

div>

7-1 Digital triangle (30 minutes)

7-1 Digital triangle (30 points)

Given a digital triangle composed of n rows of numbers, as shown in the figure below. Try to design an algorithm to calculate a path from the top to the bottom of the triangle (each step can go down the left oblique line or down the right oblique line) to maximize the sum of the numbers that the path passes.

QQ screenshot20170929023616.jpg

Input format:

There are n+1 lines of input:

The first line is the number of lines of the digital triangle n, 1<=n<=100.

The next n rows are the numbers in each row of the number triangle. All numbers are between 0..99.

Output format:

Output the value of the maximum path.

Input example:

A set of input is given here. For example:

5

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

Sample output:

The corresponding output is given here. For example:

30

Given a number consisting of n lines The digital triangle is shown in the figure below. Try to design an algorithm to calculate a path from the top to the bottom of the triangle (each step can go down the left oblique line or down the right oblique line) to maximize the sum of the numbers that the path passes.

QQ screenshot20170929023616.jpg

Input format:

There are n+1 lines of input:

The first line is the number of lines of the digital triangle n, 1<=n<=100.

The next n rows are the numbers in each row of the number triangle. All numbers are between 0..99.

Output format:

Output the value of the maximum path.

Input example:

A set of input is given here. For example:

5

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

Sample output:

The corresponding output is given here. For example:

30

Given a digital triangle composed of n rows of numbers, as shown in the figure below. Try to design an algorithm to calculate a path from the top to the bottom of the triangle (each step can go down the left oblique line or down the right oblique line) to maximize the sum of the numbers that the path passes.

QQ screenshot20170929023616.jpg

Input format:

There are n+1 lines of input:

The first line is the number of lines of the digital triangle n, 1<=n<=100.

The next n rows are the numbers in each row of the number triangle. All numbers are between 0..99.

Output format:

Output the value of the maximum path.

Input example:

A set of input is given here. For example:

5

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

Sample output:

The corresponding output is given here. For example:

30

Generally, when you encounter this kind of problem, you only need to start from the end point, and you will find that the path value to the end point can only be m[i-1][j] or m[i-1][j-1] plus yourself In this way, the problem of reaching the end point is transformed into the value of reaching the second-to-last grid, and so on.

#include

using namespace std;

int main()
{
int n,i,j;
cin
>>n;
int a[101][101];
int d[101][101];
for(i=1;i<101;i++)
{
for(j=1;j<101;j++)
{
a[i][j]
=0;
}
}
for(i=1;i<=n ;i++)
{
for(j=1;j<=i ;j++)
{
cin
>>a[i][j];
}
}

for(j=1;j<=n;j++)
{
d[n][j]
=a[n][j];
}
for(i=n-1;i> =1;i--)
{
for(j=1;j<=n ;j++)
{
if(d[i+1][j] >d[i+1][j+1])
{
d[i][j]
=d[i+1][j]+a[i][j];
}
else
{
d[i][j]
=d[i+1][j+1]+a[i][j];
}
}
}
cout
<1][1< span style="color: #000000;">];
}

Of course, it is also possible to directly overwrite the a array without creating the d array

Conclusion: This kind of direction-oriented question At the end, think about each situation clearly, and then get the maximum and minimum.

Other issues: Tolls for merchants, the problem of finding the minimum operands of sub-segments

2. The direction is uncertain or free, the starting and ending points are determined:

3-2 The problem of renting a yacht (22 points)

The source of the topic: Wang Xiaodong, “Algorithm Design and Analysis”

The Yangtze River Yacht Club has set up n yacht rental stations 1, 2, …, n on the Yangtze River. Tourists can rent yachts at these yacht rental stations and return the yachts at any yacht rental station downstream. The rent between yacht rental station i and yacht rental station j is r(i,j), 1<=i

Input format:

There is a positive integer n (n<=200) in the first line, which means there are n yacht rental stations. The next line 1 to n-1, line i represents the rent from station i to station i+1, station i+2, ..., station n.

Output format:

Output the minimum rent required from yacht rental station 1 to yacht rental station n.

Input example:

A set of input is given here. For example:

3

5 15
7

Sample output:

The corresponding output is given here. For example:

12

This question also starts from the end point to the start point. From i to n, either go directly or pass through Reactor midway stations, and the values ​​of these midway stations can be solved as sub-problems.

Recursive equation: m[i][j] starts from the ith station to j=max(m[i][k]+m[k][j],m[i][j ]) Where k

#include

using namespace std;
int main()
{
int n,i,j,k;
int yangtzeriver[200][200];
cin
>>n;
for(i=0;i)
{
yangtzeriver[i][i]=0;

}
for(i=0;i)
{
for(j=i+1;j)
{
cin>>yangtzeriver[i][j];

}
}
//cout<<"e";
for(i=n-1;i>=0;i--)
{
//cout<<" d";
for(j=i+1;j)
{
//cout<

int mini=min(yangtzeriver[i][j],yangtzeriver[i][j-1]+yangtzeriver[j-1][j]);
for(k=i+1;k)
{
int q=min(yangtzeriver[i][j],yangtzeriver[i][k]+yangtzeriver[k][j]);
//cout<
if(q<mini)
{
mini
=q;
}
}
//cout<
yangtzeriver[i][j]=mini;
}
}
cout
<0
][n-1];

如:3-1,3-3

3.方向确定,起终点不自由

一般采用方法是记录最大值

如:

3-2 租用游艇问题 (22 分)

 

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:12

一般遇到这种题,就不要把思维局限在终点。要这样想:从任意一个数开始,如果前面一堆数<0,
那以他为底的尾串就是自己,否则是前面一堆数加上这个数得到递归方程m[j]=max(m[j-1]+num[j],num[j]),
或者if num[j]<0,m[j]=num[j],else m[j]=(m[j-1]+num[j])
代码省略 自己看书
//看书


(当然 直接分治法方法加备忘录 也是可以的)

4.都没有 自己挑 如0-1背包
0-1背包:给定种物品和一个容量为的背包,物品的重量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装入背包中的物品的总价值最大。其中,每种物品只有全部装入背包或不装入背包两种选择。
这种题目二维数组的代表意义会十分的奇怪,比如说在0-1背包中,一个数代表从几号物品开始装,另一个数代表容量。
把二维数组顺序搞明白后,就会明显发现m[i][j]=max(m[i+1][j-i的价值],m[i+1][j])【前提:能装的下(j>i的价值),装不下直接m[i+1][j]】
然后把最后一行填好,就能往上填表了


#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity;j++)
{
if(j1])
{
bag[n
-1][j]=0;
}
else bag[n-1][j]=percapity[n-1];
}
for(i=n-2;i>=0;i--)
{
for(j=1;j<=capity;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1][j];
}
}
cout
<0][capity];
}


一般情况下,我们可以根据表之前的结果得到m[i][j]的结果,通常需要比较i,j和递归式里面i,j的关系,从而得到i和j在填表for循环里面的顺序,从而求i和j究竟递增,还是递增。一般递归式里面i比原i大递减,否则递增,j同理。

一般遇到这种题只需要从终点入手,就会发现到终点的路径值只能是m[i-1][j]或者m[i-1][j-1]再加自己的值,这样子到终点问题就被转化成为了到达倒数第二层格子的值,以此类推。

#include

using namespace std;

int main()
{
int n,i,j;
cin
>>n;
int a[101][101];
int d[101][101];
for(i=1;i<101;i++)
{
for(j=1;j<101;j++)
{
a[i][j]
=0;
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
cin
>>a[i][j];
}
}

for(j=1;j<=n;j++)
{
d[n][j]
=a[n][j];
}
for(i=n-1;i>=1;i--)
{
for(j=1;j<=n;j++)
{
if(d[i+1][j]>d[i+1][j+1])
{
d[i][j]
=d[i+1][j]+a[i][j];
}
else
{
d[i][j]
=d[i+1][j+1]+a[i][j];
}
}
}
cout
<1][1];
}

当然不创建d数组而直接覆盖a数组也是可以的

结论:这种确定方向的题,从终点把每个情况想清楚,然后得出最大最小即可。

其他问题:商人过路费,求子段最小操作数问题

2.方向不确定或者自由,起终点确定:

3-2 租用游艇问题 (22 分)

 

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:

12

这道题同样从终点想到起点,从i到n,要么直接过去,要么经过一堆中途站,而这些中途站所在值可以作为子问题求解。

递归方程:m[i][j]从第i个站出发到j=max(m[i][k]+m[k][j],m[i][j])其中k

#include

using namespace std;
int main()
{
int n,i,j,k;
int yangtzeriver[200][200];
cin
>>n;
for(i=0;i)
{
yangtzeriver[i][i]=0;

}
for(i=0;i)
{
for(j=i+1;j)
{
cin>>yangtzeriver[i][j];

}
}
//cout<<"e";
for(i=n-1;i>=0;i--)
{
//cout<<" d";
for(j=i+1;j)
{
//cout<

int mini=min(yangtzeriver[i][j],yangtzeriver[i][j-1]+yangtzeriver[j-1][j]);
for(k=i+1;k)
{
int q=min(yangtzeriver[i][j],yangtzeriver[i][k]+yangtzeriver[k][j]);
//cout<
if(q<mini)
{
mini
=q;
}
}
//cout<
yangtzeriver[i][j]=mini;
}
}
cout
<0
][n-1];

如:3-1,3-3

3.方向确定,起终点不自由

一般采用方法是记录最大值

如:

3-2 租用游艇问题 (22 分)

 

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:12

一般遇到这种题,就不要把思维局限在终点。要这样想:从任意一个数开始,如果前面一堆数<0,
那以他为底的尾串就是自己,否则是前面一堆数加上这个数得到递归方程m[j]=max(m[j-1]+num[j],num[j]),
或者if num[j]<0,m[j]=num[j],else m[j]=(m[j-1]+num[j])
代码省略 自己看书
//看书


(当然 直接分治法方法加备忘录 也是可以的)

4.都没有 自己挑 如0-1背包
0-1背包:给定种物品和一个容量为的背包,物品的重量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装入背包中的物品的总价值最大。其中,每种物品只有全部装入背包或不装入背包两种选择。
这种题目二维数组的代表意义会十分的奇怪,比如说在0-1背包中,一个数代表从几号物品开始装,另一个数代表容量。
把二维数组顺序搞明白后,就会明显发现m[i][j]=max(m[i+1][j-i的价值],m[i+1][j])【前提:能装的下(j>i的价值),装不下直接m[i+1][j]】
然后把最后一行填好,就能往上填表了


#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity;j++)
{
if(j1])
{
bag[n
-1][j]=0;
}
else bag[n-1][j]=percapity[n-1];
}
for(i=n-2;i>=0;i--)
{
for(j=1;j<=capity;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1][j];
}
}
cout
<0][capity];
}


一般情况下,我们可以根据表之前的结果得到m[i][j]的结果,通常需要比较i,j和递归式里面i,j的关系,从而得到i和j在填表for循环里面的顺序,从而求i和j究竟递增,还是递增。一般递归式里面i比原i大递减,否则递增,j同理。

一般遇到这种题只需要从终点入手,就会发现到终点的路径值只能是m[i-1][j]或者m[i-1][j-1]再加自己的值,这样子到终点问题就被转化成为了到达倒数第二层格子的值,以此类推。

#include

using namespace std;

int main()
{
int n,i,j;
cin
>>n;
int a[101][101];
int d[101][101];
for(i=1;i<101;i++)
{
for(j=1;j<101;j++)
{
a[i][j]
=0;
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
cin
>>a[i][j];
}
}

for(j=1;j<=n;j++)
{
d[n][j]
=a[n][j];
}
for(i=n-1;i>=1;i--)
{
for(j=1;j<=n;j++)
{
if(d[i+1][j]>d[i+1][j+1])
{
d[i][j]
=d[i+1][j]+a[i][j];
}
else
{
d[i][j]
=d[i+1][j+1]+a[i][j];
}
}
}
cout
<1][1];
}

当然不创建d数组而直接覆盖a数组也是可以的

结论:这种确定方向的题,从终点把每个情况想清楚,然后得出最大最小即可。

其他问题:商人过路费,求子段最小操作数问题

2.方向不确定或者自由,起终点确定:

3-2 租用游艇问题 (22 分)

 

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:

12

这道题同样从终点想到起点,从i到n,要么直接过去,要么经过一堆中途站,而这些中途站所在值可以作为子问题求解。

递归方程:m[i][j]从第i个站出发到j=max(m[i][k]+m[k][j],m[i][j])其中k

#include

using namespace std;
int main()
{
int n,i,j,k;
int yangtzeriver[200][200];
cin
>>n;
for(i=0;i)
{
yangtzeriver[i][i]=0;

}
for(i=0;i)
{
for(j=i+1;j)
{
cin>>yangtzeriver[i][j];

}
}
//cout<<"e";
for(i=n-1;i>=0;i--)
{
//cout<<" d";
for(j=i+1;j)
{
//cout<

int mini=min(yangtzeriver[i][j],yangtzeriver[i][j-1]+yangtzeriver[j-1][j]);
for(k=i+1;k)
{
int q=min(yangtzeriver[i][j],yangtzeriver[i][k]+yangtzeriver[k][j]);
//cout<
if(q<mini)
{
mini
=q;
}
}
//cout<
yangtzeriver[i][j]=mini;
}
}
cout
<0
][n-1];

如:3-1,3-3

3.方向确定,起终点不自由

一般采用方法是记录最大值

如:

3-2 租用游艇问题 (22 分)

 

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:12

一般遇到这种题,就不要把思维局限在终点。要这样想:从任意一个数开始,如果前面一堆数<0,
那以他为底的尾串就是自己,否则是前面一堆数加上这个数得到递归方程m[j]=max(m[j-1]+num[j],num[j]),
或者if num[j]<0,m[j]=num[j],else m[j]=(m[j-1]+num[j])
代码省略 自己看书
//看书


(当然 直接分治法方法加备忘录 也是可以的)

4.都没有 自己挑 如0-1背包
0-1背包:给定种物品和一个容量为的背包,物品的重量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装入背包中的物品的总价值最大。其中,每种物品只有全部装入背包或不装入背包两种选择。
这种题目二维数组的代表意义会十分的奇怪,比如说在0-1背包中,一个数代表从几号物品开始装,另一个数代表容量。
把二维数组顺序搞明白后,就会明显发现m[i][j]=max(m[i+1][j-i的价值],m[i+1][j])【前提:能装的下(j>i的价值),装不下直接m[i+1][j]】
然后把最后一行填好,就能往上填表了


#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity;j++)
{
if(j1])
{
bag[n
-1][j]=0;
}
else bag[n-1][j]=percapity[n-1];
}
for(i=n-2;i>=0;i--)
{
for(j=1;j<=capity;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1][j];
}
}
cout
<0][capity];
}


一般情况下,我们可以根据表之前的结果得到m[i][j]的结果,通常需要比较i,j和递归式里面i,j的关系,从而得到i和j在填表for循环里面的顺序,从而求i和j究竟递增,还是递增。一般递归式里面i比原i大递减,否则递增,j同理。

#include

using namespace std;

int main()
{
int n,i,j;
cin
>>n;
int a[101][101];
int d[101][101];
for(i=1;i<101;i++)
{
for(j=1;j<101;j++)
{
a[i][j]
=0;
}
}
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
cin
>>a[i][j];
}
}

for(j=1;j<=n;j++)
{
d[n][j]
=a[n][j];
}
for(i=n-1;i>=1;i--)
{
for(j=1;j<=n;j++)
{
if(d[i+1][j]>d[i+1][j+1])
{
d[i][j]
=d[i+1][j]+a[i][j];
}
else
{
d[i][j]
=d[i+1][j+1]+a[i][j];
}
}
}
cout
<1][1];
}

3-2 租用游艇问题 (22 分)

 

3-2 租用游艇问题 (22 分)

3-2 租用游艇问题 (22 分)

 

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:

12

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:

12

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:

12

#include

using namespace std;
int main()
{
int n,i,j,k;
int yangtzeriver[200][200];
cin
>>n;
for(i=0;i)
{
yangtzeriver[i][i]=0;

}
for(i=0;i)
{
for(j=i+1;j)
{
cin>>yangtzeriver[i][j];

}
}
//cout<<"e";
for(i=n-1;i>=0;i--)
{
//cout<<" d";
for(j=i+1;j)
{
//cout<

int mini=min(yangtzeriver[i][j],yangtzeriver[i][j-1]+yangtzeriver[j-1][j]);
for(k=i+1;k)
{
int q=min(yangtzeriver[i][j],yangtzeriver[i][k]+yangtzeriver[k][j]);
//cout<
if(q<mini)
{
mini
=q;
}
}
//cout<
yangtzeriver[i][j]=mini;
}
}
cout
<0
][n-1];

3-2 租用游艇问题 (22 分)

 

3-2 租用游艇问题 (22 分)

3-2 租用游艇问题 (22 分)

 

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:12

一般遇到这种题,就不要把思维局限在终点。要这样想:从任意一个数开始,如果前面一堆数<0,
那以他为底的尾串就是自己,否则是前面一堆数加上这个数得到递归方程m[j]=max(m[j-1]+num[j],num[j]),
或者if num[j]<0,m[j]=num[j],else m[j]=(m[j-1]+num[j])
代码省略 自己看书
//看书


(当然 直接分治法方法加备忘录 也是可以的)

4.都没有 自己挑 如0-1背包
0-1背包:给定种物品和一个容量为的背包,物品的重量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装入背包中的物品的总价值最大。其中,每种物品只有全部装入背包或不装入背包两种选择。
这种题目二维数组的代表意义会十分的奇怪,比如说在0-1背包中,一个数代表从几号物品开始装,另一个数代表容量。
把二维数组顺序搞明白后,就会明显发现m[i][j]=max(m[i+1][j-i的价值],m[i+1][j])【前提:能装的下(j>i的价值),装不下直接m[i+1][j]】
然后把最后一行填好,就能往上填表了


#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity;j++)
{
if(j1])
{
bag[n
-1][j]=0;
}
else bag[n-1][j]=percapity[n-1];
}
for(i=n-2;i>=0;i--)
{
for(j=1;j<=capity;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1][j];
}
}
cout
<0][capity];
}


一般情况下,我们可以根据表之前的结果得到m[i][j]的结果,通常需要比较i,j和递归式里面i,j的关系,从而得到i和j在填表for循环里面的顺序,从而求i和j究竟递增,还是递增。一般递归式里面i比原i大递减,否则递增,j同理。

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:12

一般遇到这种题,就不要把思维局限在终点。要这样想:从任意一个数开始,如果前面一堆数<0,
那以他为底的尾串就是自己,否则是前面一堆数加上这个数得到递归方程m[j]=max(m[j-1]+num[j],num[j]),
或者if num[j]<0,m[j]=num[j],else m[j]=(m[j-1]+num[j])
代码省略 自己看书
//看书


(当然 直接分治法方法加备忘录 也是可以的)

4.都没有 自己挑 如0-1背包
0-1背包:给定种物品和一个容量为的背包,物品的重量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装入背包中的物品的总价值最大。其中,每种物品只有全部装入背包或不装入背包两种选择。
这种题目二维数组的代表意义会十分的奇怪,比如说在0-1背包中,一个数代表从几号物品开始装,另一个数代表容量。
把二维数组顺序搞明白后,就会明显发现m[i][j]=max(m[i+1][j-i的价值],m[i+1][j])【前提:能装的下(j>i的价值),装不下直接m[i+1][j]】
然后把最后一行填好,就能往上填表了


#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity;j++)
{
if(j1])
{
bag[n
-1][j]=0;
}
else bag[n-1][j]=percapity[n-1];
}
for(i=n-2;i>=0;i--)
{
for(j=1;j<=capity;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1][j];
}
}
cout
<0][capity];
}


一般情况下,我们可以根据表之前的结果得到m[i][j]的结果,通常需要比较i,j和递归式里面i,j的关系,从而得到i和j在填表for循环里面的顺序,从而求i和j究竟递增,还是递增。一般递归式里面i比原i大递减,否则递增,j同理。

题目来源:王晓东,《算法设计与分析》

长江游艇俱乐部在长江上设置了n个游艇出租站1,2,…,n。游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇。游艇出租站i到游艇出租站j之间的租金为r(i,j),1<=i

输入格式:

第1 行中有1 个正整数n(n<=200),表示有n个游艇出租站。接下来的第1到第n-1 行,第i行表示第i站到第i+1站,第i+2站, ... , 第n站的租金。

输出格式:

输出从游艇出租站1 到游艇出租站n所需的最少租金。

输入样例:

在这里给出一组输入。例如:

3

5 15
7

输出样例:

在这里给出相应的输出。例如:12

一般遇到这种题,就不要把思维局限在终点。要这样想:从任意一个数开始,如果前面一堆数<0,
那以他为底的尾串就是自己,否则是前面一堆数加上这个数得到递归方程m[j]=max(m[j-1]+num[j],num[j]),
或者if num[j]<0,m[j]=num[j],else m[j]=(m[j-1]+num[j])
代码省略 自己看书
//看书


(当然 直接分治法方法加备忘录 也是可以的)

4.都没有 自己挑 如0-1背包
0-1背包:给定种物品和一个容量为的背包,物品的重量是,其价值为,背包问题是如何使选择装入背包内的物品,使得装入背包中的物品的总价值最大。其中,每种物品只有全部装入背包或不装入背包两种选择。
这种题目二维数组的代表意义会十分的奇怪,比如说在0-1背包中,一个数代表从几号物品开始装,另一个数代表容量。
把二维数组顺序搞明白后,就会明显发现m[i][j]=max(m[i+1][j-i的价值],m[i+1][j])【前提:能装的下(j>i的价值),装不下直接m[i+1][j]】
然后把最后一行填好,就能往上填表了


#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity;j++)
{
if(j1])
{
bag[n
-1][j]=0;
}
else bag[n-1][j]=percapity[n-1];
}
for(i=n-2;i>=0;i--)
{
for(j=1;j<=capity;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1][j];
}
}
cout
<0][capity];
}


一般情况下,我们可以根据表之前的结果得到m[i][j]的结果,通常需要比较i,j和递归式里面i,j的关系,从而得到i和j在填表for循环里面的顺序,从而求i和j究竟递增,还是递增。一般递归式里面i比原i大递减,否则递增,j同理。

//看书

#include

using namespace std;
int main()
{
int n,capity,i,j;
cin
>>n>>capity;
int item[100],percapity[100];
for(i=0;i)
{
cin>>item[i];
cin
>>percapity[i];
}
int bag[100][100];
for(j=0;j<=capity;j++)
{
if(j1])
{
bag[n
-1][j]=0;
}
else bag[n-1][j]=percapity[n-1];
}
for(i=n-2;i>=0;i--)
{
for(j=1;j<=capity;j++)
{
if(j>=percapity[i])
{
bag[i][j]
=max(bag[i+1][j],bag[i+1][j-percapity[i]]+item[i]);
}
else bag[i][j]=bag[i+1][j];
}
}
cout
<0][capity];
}

Leave a Comment

Your email address will not be published.