POJ 3666 Making the Grade(动态规划)

来源:互联网 发布:微博seo 编辑:程序博客网 时间:2024/05/16 12:42

大概题意:给出n个数字组成序列a,然后再找到一个序列b,从1至n,abs(a[i]-b[i])的总和最小,其中序列b是非严格单调序列,要么是要么是非递减序列,要么是非递增序列...

看完题目,河南省14年省赛题....大一下学期参加那场,这个题目做了好久果然没A出来,但是用的方法是构造出来b这个序列,先对原序列排序,然后开始构造成出第一个数字,以后每个数字要么是前一个数字要么就是自身...

现在想来原来的思路有几个漏洞。。比赛完之后当时也尝试去完成这个代码,但是只是记得样例,样例很好过...没找到题目,现在看到了想到的别的思路。

这个题目貌似是《挑战程序设计》,但是在家里手边没书...我程序中dp数组是一维的,但是是滚动数组,这个优化是01背包优化的思路...

大概思路:dp[i][j]就是完成了前i个,目标序列最后一个数字是排序后的第j个数字...不难想dp[i][j]其实就是dp[i-1][从1到j]里面损耗最小的+abs(a[i]-b[j])....题目说可费非增可非递减,排序两次比较麻烦,不如直接把原序列颠倒位置....

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>using namespace std;#define inf 1<<30int dp[2333],n;int Dp(int a[],int num[]){    int ans=inf;    memset(dp,0,sizeof(dp));    for(int i=1;i<=n;i++)    {        int t=inf;        for(int j=1;j<=n;j++)        {           t=min(t,dp[j]);//此时的dp[j]为dp[i-1][j]           dp[j]=t+abs(a[i]-num[j]);//此时的dp[j]代表的意义从dp[i-1][j]更新为dp[i][j]        }    }    for(int i=1;i<=n;i++)        ans=min(ans,dp[i]);    return ans;}int main(){    int a[2333],b[2333],num[2333];    while(cin>>n)    {        for(int i=1;i<=n;i++)        {            cin>>a[i];            b[n-i+1]=a[i];            num[i]=a[i];        }        sort(num+1,num+n+1);        int ans;        ans=min(Dp(a,num),Dp(b,num));        cout<<ans<<endl;    }    return 0;}


0 0
原创粉丝点击