动态规划 III——C - Travel

来源:互联网 发布:复杂网络基础概论 编辑:程序博客网 时间:2024/05/18 01:32
本题思路:(1)在理清思路之前,首先要理清题意。而理清题意时,要注意涉及哪几个变化因素,并且要把文字转换成计算机语言来描述。

如本题,变化因素有:城市数量、旅游天数、过市费用、从市赚取得钱。计算机语言描述如下(结合题目给出的已有变量名):

n表示城市数量,m表示旅游天数。结合例子,从城市i到城市j的费用可以表示成cost[i][j],至于要呆几天,过市的费用是不受影响的;第i天在城市j赚到的钱可以表示成inc[i][j],至于

昨天从哪个城市来的,并不影响今天在这个城市赚的钱。

(2)理清题意之后,开始看问题。看问题时,同样要把问题的描述转换成计算机语言。

问题文字描述;求3天游历3个城市得到的最大收益。可以用dp[i][j]表示第i天游历城市j得到的最大收益,即是旅游到第i天时人在城市j所得到的最大收益(包括之前得到的收益,

不断累加的一个结果)。

(3)最后分析问题。3天游历3个城市得到的最大收益。(起始站在城市1)下面将问题小化

1、假设一天游历一个城市。

——>这一天我可能在城市1、城市2、城市3。问题解决:求出dp[1][1]、dp[1][2]、dp[1][3]三者的值,再取最大值就好。

——>dp[1][i]=0-cost[1][i]+inc[1][i];           (注意今天的最大收益是有昨天最大收益的累加,第i天的收益也要有前面i-1天的收益累加)

2、假设两天游历两个城市。

——>第一天我可能在城市1、城市2、城市3。同假设1,只是不取假设1中的最大值。

——>第二天我可能在城市1、城市2、城市3。问题解决:求出dp[2][1]、dp[2][2]、dp[2][3]三者的值,再取最大值就好。

——>若第二天在城市1,则dp[2][1]=dp[1][i]-cost[i][1]+inc[2][1];  //i指的是:前一天从城市i到城市1(i=1,2,3)

——>若第二天在城市2,则dp[2][2]=dp[1][i]-cost[i][2]+inc[2][2];  //i指的是:前一天从城市i到城市2(i=1,2,3)

——>若第二天在城市3,则dp[2][3]=dp[1][i]-cost[i][3]+inc[2][3];  //i指的是:前一天从城市k到城市3(i=1,2,3)

——>dp[2][j]=dp[1][i]-cost[i][j]+inc[2][j]

3、假设三天游历三个城市。

——>第一天我可能在城市1、城市2、城市3。同假设1,只是不取假设1中的最大值。

——>第二天我可能在城市1、城市2、城市3。同假设2,只是不取假设2中的最大值。

——>第三天我可能在城市1、城市2、城市3。问题解决:求出dp[3][1]、dp[3][2]、dp[3][3]三者的值,再取最大值就好。

——>若第三天在城市1,则dp[3][1]=dp[2][i]-cost[i][1]+inc[3][1];  //i指的是:前一天从城市i到城市1(i=1,2,3)

——>若第三天在城市2,则dp[3][2]=dp[2][i]-cost[i][2]+inc[3][2];  //i指的是:前一天从城市i到城市2(i=1,2,3)

——>若第三天在城市3,则dp[3][3]=dp[2][i]-cost[i][3]+inc[3][3];  //i指的是:前一天从城市i到城市3(i=1,2,3)

——>dp[3][j]=dp[2][i]-cost[i][j]+inc[3][j]

(4)观察:dp[1][i]、dp[2][j]、dp[3][j],可以发现后一个式子的求解只与前一个式子有关。符合(动态规划特征:当前状态与上一状态相关)

写出通用公式——>dp[i][j]=dp[i-1][k]-cost[k][j]+inc[i][j]

1、对通用公式进行分析:1)有三个变量名:i(指天数)、j(指城市)、k(指城市)。

2)变量名变化次数的多少,由多到少排序:k,j,i;

3)与公式中变量名相关的因素:k(n),j(n),i(m);由这三点分析能够写出一个大循环(三重)

2、对动态边界进行确定:往往将大循环第一重的第一个赋值(i=1,注意,这时k=1)代入通用公式:dp[1][j]=dp[0][1]-cost[1][j]+inc[1][j]

——>dp[0][1]、cost[1][j]、inc[1][j]就是边界。

——>边界的式子需要在大循环的前面先求解出具体的值。

<span style="font-family: Arial, Helvetica, sans-serif;">下面是伪代码演示:</span>
dp[0][1]=0;for(...;i<=n;...)              //包含了cost[1][j]for(...;j<=n;...)scanf(数据输入);for(...;i<=m;..)              //包含了inc[1][j]for(...;j<=n;...)scanf(数据输入);for(..;i<=m;..)               //(三重)大循环,相当于求出了一个二维数组dp[m][n]for( ...;j<=n;...)for( ...;k<=n;...)dp[i][j]=max(dp[i][j],通用公式)     //dp数组要在前面初始化,赋予极小的值(属于技巧性,因为动态肯定要比较,这里是累加性的,只能和自身比较)。方便这里对dp[i][j]和通用公式的初次比较和获取最大值。ans=0;                     //通过比较dp[3][i]找出最大值,解决问题。这里ans=0和“前面dp数组要在前面初始化,赋予极小的值”的作用一样。for(int i=1;i<=n;i++)ans=max(ans,dp[3][i])
</pre><pre name="code" class="cpp">下面是C++代码演示:
#include<stdio.h>#include<math.h>#include<algorithm>using namespace std;int cost[105][105];int inc[105][105];int dp[105][105];int main(){int n,m;while(scanf("%d%d",&n,&m)){if(!n&&!m)break;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&cost[i][j]);for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)scanf("%d",&inc[i][j]);memset(dp,-9999999,sizeof(dp));dp[0][1]=0;for(int i=1;i<=m;i++)for(int j=1;j<=n;j++)for(int k=1;k<=n;k++)dp[i][j]=max(dp[i][j],dp[i-1][k]-cost[k][j]+inc[i][j]);int ans=0;for(int i=1;i<=n;i++)ans=max(ans,dp[m][i]);printf("%d\n",ans);}}



0 0
原创粉丝点击