POJ-3366-Making the Grade

POJ-3366-Making the Grade_第1张图片

思路:数组要变为有序数组,首先考虑正序数组a[n],对于dp[i][j]表示 a[i]变为a[j]时前i个元素有序的最少步数(至于为什么只考虑数组中的元素,我也不大懂。。。)因此 状态转换方程为

dp[i][j]=abs(a[i]-a[j])+min{dp[i-1][k]}  (a[j]>=a[k]) 

这样需要对 i,j,k遍历,因此时间复杂度为 O(n^3),为TLE,观察转换方程可知,min{dp[i-1][k]}只需要其最小值,所有可以先将最小值保存在dp[i-1][k]中,而a[j]>=a[k]必须成立,因此可以将a[n]由小到大排序保存在d[n]中,那么转换方程就可以变成

dp[i][j]=abs(a[i]-a[j])+dp[i-1][j]; (dp[i][j]表示a[i]变为d[j]时前i个元素有序的最少步数,而最小值保存在dp[i-1][j]中,因此dp[i][j]要保存前j的最小值 dp[i][j]=min(dp[i][j],dp[i][j-1]);

而dp[i][j]也可以转换为一维dp: dp[j]=min(abs(a[i]-d[j])+dp[j],dp[j-1]);

Code :

#include
#include
#include
#include
using namespace std;
typedef long long LL;

const LL INF=1e18;
const int MAX_N=2005;
int n;
int a[MAX_N],d[MAX_N];
//LL dd[MAX_N][MAX_N];	//最小值
LL dp[MAX_N];
 
LL Find(void);
int main()
{
	ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>a[i];
        d[i]=a[i];
    }
    sort(d+1,d+n+1);
    LL s1=Find();
    for(int i=1,t;i<=n/2;++i)
    {
    	t=d[i];	d[i]=d[n-i+1];	d[n-i+1]=t;
	}
//	memset(dd,0,sizeof(dd));
	memset(dp,0,sizeof(dp));
	LL s2=Find();
	cout<

 

你可能感兴趣的:(DP,POJ)