开场先来一段百度百科:
动态规划中本阶段的状态往往是上一阶段状态和上一阶段决策的结果。如果给定了第K阶段的状态Sk以及决策uk(Sk),则第K+1阶段的状态Sk+1也就完全确定。也就是说Sk+1与Sk,uk之间存在一种明确的数量对应关系,记为Tk(Sk,uk),即有Sk+1= Tk(Sk,uk)。 这种用函数表示前后阶段关系的方程,称为状态转移方程。在上例中状态转移方程为 Sk+1= uk(Sk) 。
poj1018题意:
目前有一个公司需要购进宽带设备,每种设备有多款机器供选择,每种设备都需购进一台,现给出每台设备的带宽p与价格q,要求选择设备的最小带宽min(p)/add(q)(其中min(p)表示所有购进设备中最小的带宽,add(q)表示所有购进设备的价格之和)为最大,并求出该值。
输入:
第一行表示测试用例个数与设备种类数
接下来每一行第一个数表示每种设备有多少款机器,后面紧跟每款机器的带宽与价格。
题目读完,还是强调直觉,这题可使用动态规划得解;
分析动态规划关键点:
非常明显这个问题可以进行分解,分解如下:
设dp[i][j]为前i组带宽为j的最小价格和,那么状态转移方程为dp[i][j]=min{dp[i][j] , dp[i-1][k]+q},表示dp[i][j]为在两种情况中取最小值:
1.j正好为最小带宽,dp[i][j]就为前i组带宽为j的价格和
2.之前的带宽k为最小带宽,价格为之前价格再加上q
代码如下:
#include<iostream> #include<algorithm> using namespace std; const int inf = 0x3f3f3f3f; int a[120][1100]; //状态转移方程:dp[i][j] = min( dp[i][j] , dp[i-1][k]+q ) //dp[i][j]表示前i组带宽为j的最小价格 int main(){ int n; cin>>n; while(n--){ int m; cin>>m; for(int i=1;i<=m;i++){ for(int j=0;j<1100;j++){ a[i][j]=inf; } } for(int i=1;i<=m;i++){ int num; cin>>num; for(int j=0;j<num;j++){ int p,q; cin>>p>>q; if(i==1){ a[i][p]=min(a[1][p],q); }else{ //之所以从0遍历到1200: //1.预估带宽最大到1200 //2.保证所有的带宽与对应的最小价格都被存到二维数组中,最后所求最小价格即为a[3][min带宽] for(int k=0;k<1100;k++){ if(a[i-1][k]!=inf){ if(k<=p){ a[i][k]=min(a[i][k],a[i-1][k]+q); }else{ a[i][p]=min(a[i][p],a[i-1][k]+q); } } } } } } double res=0; for(int i=0;i<1100;i++){ if(a[m][i]!=inf){ double temp = (double)i/a[m][i]; if(temp>res){ res=temp; } } } printf("%.3lf ",res); } return 0; }