/*
动态规划题的思路:设定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;
}/*
动态规划题的思路:设定dp[i],dp[i][j]等数字量进行求解,这个数字量就称为:状