ACM-ICPC Live Archive 2031 Dance Dance Revolution

动态规划

黑书的例题,老题了,2000年的国赛题,题意看黑书吧,太长了。。。比较典型的按阶段性决策,整个dp还是不难想的,1A

分析在代码中

/*

按时间决策的DP,或者说按阶段性决策

当前要跳的格子出现了,那么怎么跳其实只有两种选择,用左脚去踩或者右脚去踩

所以要枚举前一个格子结束的时候,左右脚在什么地方,如果用左脚踩会产生多少花费,用右脚踩会产生多少花费

dp[i][l][r]表示踩完第i次,左脚在l这个格子上,右脚在r这个格子上的最小花费

那么最终要找的答案在dp[n][l][r]中,所以要扫描一次dp[n]找到最大值

由题目的性质就知道可以使用滚动数组,而且题目也没提到序列的长度,所以用滚动数组也更为保险

*/

#include <cstdio>

#include <cstring>

#define min(a,b) a<b?a:b

#define INF 0x3f3f3f3f



long long dp[2][5][5]; //滚动数组,dp[0]上一次,dp[1]这一次



int cal(int x ,int s)

{

    int cost;

    if(x==0) cost=2; //从中心到任何位置都是2

    else if(x==s) cost=1; //原地踩为1

    else if((x==1 && s==3)||(x==3 && s==1)||(x==2 && s==4)||(x==4 && s==2))

        cost=4; //移动到对面

    else //相邻的移动

        cost=3;

    return cost;

}



int main()

{

    int s;

    while(scanf("%d",&s)!=EOF && s)

    {

        memset(dp,0x3f,sizeof(dp));

        //一开始两个脚都在中心

        dp[0][s][0]=2; //用左脚去踩第一个

        dp[0][0][s]=2; //用右脚去踩第一个

        while(scanf("%d",&s) && s)

        {

            for(int l=0; l<5; l++) //初始化

                for(int r=0; r<5; r++)

                    dp[1][l][r]=INF;

            //用左脚去踩,那么右脚和之前的位置是相同的

            //右脚不动,那么先枚举右脚的位置,但是右脚不能站在当前要踩的位置

            //再枚举左脚之前站的位置,左脚之前站的位置与右脚位置也不能相同

            for(int r=0; r<5; r++)

                if(r!=s) //枚举右脚,但是右脚不能与当前位置相同

                    for(int l=0; l<5; l++)

                        if(l!=r) //左脚和右脚位置不相同

                        {

                            int cost=cal(l,s); //计算这样移动的花费

                            dp[1][s][r] = min(dp[1][s][r] , dp[0][l][r]+cost);

                        }

            //同样地用右脚去踩,那么左脚和之间的位置是相同的

            //左脚不动,那么先枚举左脚的位置,但是左脚不能与当前要踩的格子相同

            //再枚举右脚之前站的位置,但是右脚的位置不能和左脚位置相同

            for(int l=0; l<5; l++) //先枚举左脚

                if(l!=s)

                    for(int r=0; r<5; r++) //再枚举右脚

                        if(r!=l) //左右脚位置不同

                        {

                            int cost=cal(r,s);

                            dp[1][l][s] = min(dp[1][l][s] , dp[0][l][r]+cost);

                        }



            //滚动数组,复制过去

            for(int l=0; l<5; l++)

                for(int r=0; r<5; r++)

                    dp[0][l][r]=dp[1][l][r];

        }



        long long ans=INF;

        for(int l=0; l<5; l++)

            for(int r=0; r<5; r++)

                ans = min(ans,dp[0][l][r]);

        printf("%lld\n",ans);

    }

    return 0;

}

 

 

你可能感兴趣的:(hive)