zstu2552---马棚问题 DP

题目来源:http://acmpj.zstu.edu.cn/JudgeOnline/showproblem?problem_id=2552

动态规划基本步骤(本人觉得):

1.确定数组的维数,一维,二维等等;2.弄清数组下标的含义3.找出状态转移方程式;4实现自己的想法;

本题思路:

二维数组dp[i][j],i表示前i个马棚放马完毕,j表示队列前j匹马已经进入马棚,dp[i][j]记录前j匹马放在前i个马棚里的最小不愉快系数,用f(a,b)表示只把第a匹马到第b匹马放在一个马棚里的不愉快系数;

思考得出 状态转移方程:dp[i][j]=min(dp[i-1][t]+f(t,j));注意范围:(i-1<=t<j),(i<=j<=n-(n-k))

范围得出的理由:每个马棚都至少要放一匹马;

用zero[j],one[j]两个数组记录前j匹马中黑白马的个数;

则不难得出   f(a,b)=(zero[b]-zero[a])*(one[b]-one[a]);

View Code
#include<stdio.h>
int dp[501][501],zero[501],one[501];
int main()
{
    int n,k,i,j,t,x;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        zero[0]=one[0]=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(x){zero[i]=zero[i-1];one[i]=one[i-1]+1;}
            else {zero[i]=zero[i-1]+1;one[i]=one[i-1];}
        }
        dp[1][1]=0;
        for(j=2;j<=n-k+1;j++)
            dp[1][j]=one[j]*zero[j];
        for(i=2;i<=k;i++)
        {
            for(j=i;j<=n-(k-i);j++)
            {
                int min=999999;
                for(t=i-1;t<j;t++)
                {
                    int temp=(one[j]-one[t])*(zero[j]-zero[t]);
                    if(dp[i-1][t]+temp<min)min=dp[i-1][t]+temp;
                }
                dp[i][j]=min;
            }
        }
        printf("%d\n",dp[k][n]);
    }
    return 0;
}

做完一道题后,再看看别人的做法,发现可以用一维数组,结果又写了个一维数组,思想是完全一样的,
只是用了dp[j],省去i;

理由:在递推过程中有些数据用一次就没什么用了,用了一维数组正是用了这个规律,

自己打个二维的dp[i][j],模拟一下计算过程就知道为什么可以用一维数组了;

View Code
#include<stdio.h>
int zero[550],one[550];
int dp[505];
int main()
{
    int n,k,a,i,j,t,x,temp,min;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        zero[0]=one[0]=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&x);
            if(x){one[i]=one[i-1]+1;zero[i]=zero[i-1];}
            else {one[i]=one[i-1];zero[i]=zero[i-1]+1;}
        }
        for(j=1;j<=n;++j)
        {
            dp[j]=zero[j]*one[j];
        }
        for(i=2;i<=k;i++)
        {
            for(j=n-(k-i);j>=1;j--) //思考为什么从大到小
            {
                min=999999;
                for(t=i-1;t<j;t++)
                {
                    int temp=(one[j]-one[t])*(zero[j]-zero[t]);
                    if(dp[t]+temp<min)min=dp[t]+temp;
                }
                dp[j]=min;
            }
        }
        printf("%d\n",dp[n]);
    }
    return 0;
}

 

posted @ 2012-06-29 15:03  To be an ACMan  Views(301)  Comments(0)    收藏  举报