poj3666Making the Grade【dp离散化】

来源:互联网 发布:163邮箱smtp ssl 端口 编辑:程序博客网 时间:2024/06/05 23:03

居然沦落到不到40行的dp还要翻题解再见你想咋的 这题可能唯一难就难在离散化做的少,就算告诉了状态转移方程也写不好,再说了,状态转移方程也不难啊,换到这个题就换了一个地方而已啊

方程:dp[i][j]=abs(j-a[i])+mn  i表示递推到哪位,j表示目前的最大值(这题数据只要满足不递减就可以了),mn表示前面一位的各个最大值时的花费最小值。然后离散化的思想是既然给的数据单个的值都那么大,那我莫不如排个序,用对应位置代替对应位置的数 。加油吧

p.s.时隔两日,每晚想此题久久不能入眠,深感领悟不够,遂除夕夜晚特来重温,并手写了这个表格,以下是新加的内容

关于为什么二重循环内部是当前这位的差值加的是mn,即当前大循环的最小值:

又写了二重循环出现最小值之后的部分才发现规律==对于大循环中的小循环来说,dp值得大小只可能是先下降,再增加(先考虑j表示值而不是离散化后的坐标的情况  j值最多不只是最大值)我们从原理上分析,在本次循环时。如果出现最小值的地方在上一轮出现最小值的后面,那没的说,我不可能用当前这位上次循环的dp值加上这次的差值,我肯定得找上次出现的最小值加本次的差值==因为上次出现的最小值的位置比这次小啊,我没必要让上一次非得加到我这次循环最小值那个位置,前一次比这一次小是可以的啊

/************hdu36662016.2.531656K157MSC++780B************/#include <iostream>#include<cstdio>#include<cstring>#include<algorithm>#define Abs(a) ((a)>0?(a):-(a))using namespace std;int a[2004],b[2004],n;long long dp[2004][2004],mn;int main(){  //  freopen("cin.txt","r",stdin);    while(~scanf("%d",&n))    {        for(int i=1;i<=n;i++) {scanf("%d",&a[i]);b[i]=a[i];}        sort(b+1,b+n+1);        memset(dp,0,sizeof(dp));        for(int i=1;i<=n;i++)        {            mn=dp[i-1][1];            for(int j=1;j<=n;j++)            {                mn=min(mn,dp[i-1][j]);                dp[i][j]=Abs(a[i]-b[j])+mn;            }        }        mn=dp[n][1];        for(int i=1;i<=n;i++) if(mn>dp[n][i]) mn=dp[n][i];        printf("%I64d\n",mn);    }    return 0;}


0 0
原创粉丝点击