/* 动态规划题的思路:设定dp[i],dp[i][j]等数字量进行求解,这个数字量就称为:状态。 状态:含义:是秒数当前状况的一个数字量。 特点:是数字,保存在内存中,可以表示一个状态的特征,不需要辅助信息。最重要:状态间的转移依赖于状态本身。 dp(dynamic plan,动态规划) 关键:寻找一个好的状态 状态转移:由一个或多个旧的状态得到一个新的状态的过程。例如:通过dp[i-1][j-1]推出dp[i][j]。 转移规则(状态转移方程):数字量之间的递推关系。 确定状态的转移规则:即确定怎样由前序状态递推求出后续状态。 dp问题的复杂度估计:两个字符串的长度分别为L1和L2,共有L1*L2个状态要求解,为求解每个状态,按照相应字符是否相等选取dp[i-1][j-1]+1或者max{ dp[i-1][j],dp[i][j-1]}为dp[i][j]的值,即每个状态的得出需要O(1)的时间,所以总的时间复杂度为O(L1*L2*1) 对于最长递增子序列:原数列长度为n,则状态数量为dp[n],状态转移过程中每个状态得出的复杂度为O(n),总时间复杂度为O(n*n) dp时间复杂度=状态数量*状态转移复杂度 问题:搬寝室。n件物品,n<2000.准备搬2*k(<=n)件物品。每搬一次的疲劳度和左右手之间的重量差的平方成正比。请求出办完这2*k件物品后的最低疲劳度是多少 输入:每组输入数据有2行,第一行有2个数n,k(2<=2*k<=n<2000),第二行有n个整数,分别表示n件物品的重量(<2的15次方) 输出:对应每组输入数据,输出数据只有一个表示他的最少的疲劳度,每个一行. 输入: 2 1 1 3 输出: 4 思路:设a<=b<=c<=d经计算ab,cd配对方案的累计疲劳度<=ac,bd配对方案的累计疲劳度。结论:每一对组合的两个物品重量,是原物品中重量相邻的两个物品。 先对物品排序。设dp[i][j]表示前j件物品中选择i对物品的最小疲劳度。状态来源: 1)物品j和j-1未配对,则物品j每被选择,dp[i][j]=dp[i][j-1] 2) 物品j和j-1配对,等价于配对i-1对,将j-1与j进行配对dp[i][j]=dp[i-1][j-2] + (list[j]-list[j-1])的平方 关键: 1 状态转移方程dp[i][j]= min{dp[i][j-1] ,dp[i-1][j-2] + (list[j]-list[j-1])的平方},其中dp[0][n]=0 2 dp时间复杂度=状态数量*状态转移复杂度=(k*n)*O(1)=O(k*n) 3 你要求出的值是dp[k][n] 4 注意两边的i,j需要配对。i表征k,j表征n,j=2*i 5 程序还没有运行就退出,说明你声明了一个全局变量,而且申请的空间很大,导致崩溃 6 程序发生错误,粗心:scanf("%d",&Arr[n]);dp[0][n] = 0;应该把n改成i。 7 本题技巧,j > 2*i dp[i][j]=dp[i-1][j],j<=2*i,dp[i][j]=INT_MAX,比较dp[i][j]和dp[i-1][j-2]的大小 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <algorithm> #define INT_MAX 123123123 #define NN 201 using namespace std; int partition(int* Arr,int low,int high) { int iPos = Arr[low]; while(low < high) { while(low < high && Arr[high] >= iPos) { high--; } Arr[low] = Arr[high]; while(low < high && Arr[low] <= iPos) { low++; } Arr[high] = Arr[low]; } Arr[low] = iPos; return low; } void quickSort(int* Arr,int low,int high) { if(low < high) { int iPos = partition(Arr,low,high); quickSort(Arr,low,iPos-1); quickSort(Arr,iPos+1,high); } } int main(int argc,char* argv[]) { int n,k; int dp[NN][NN]; int Arr[NN]; int i,j; while(EOF!=scanf("%d %d",&n,&k)) { //对状态数组进行初始化 for(i = 0; i <= n ; i++) { dp[0][i] = 0; } //接受输入信息 //for(i = 0; i < n ; i++) //易错,这里的i与j要与下面的进行比对质量时配对 for(i = 1 ; i <= n ; i++) { scanf("%d",&Arr[i]); } //对重量进行快速排序 quickSort(Arr,1,n); //sort(Arr,Arr+1,Arr+1+n); //开始进行动态规划 for(i = 1 ; i <= k ; i++) { //易错,j必须从2i开始 //for(j = 2 ; j <=n ; j++) for(j=2*i ; j <= n ; j++) { //如果j > 2*i表示,最后2个物品可以不配对 if(j > 2*i) { dp[i][j] = dp[i-1][j]; } //j<=2*i,最后2个物品必须配对 else { dp[i][j]=INT_MAX;//否则前j件物品配不成i对,所以其状态不能由dp[i][j-1]转移而来,dp[i][j]先设置为正无穷大 } //判定是dp[i-1][j-2]的值与其他的值比较,更新这个值 if(dp[i][j] > dp[i-1][j-2] + (Arr[j]-Arr[j-1])*(Arr[j]-Arr[j-1])) { dp[i][j] = dp[i-1][j-2] + (Arr[j]-Arr[j-1])*(Arr[j]-Arr[j-1]); } } } //最终你所要求的是dp[k][n] printf("%d\n",dp[k][n]); } system("pause"); getchar(); return 0; }