UVa:10051 Tower of Cubes(动态规划)

思路:LIS变形题,状态转移方程并不难想。

i表示第i个立方体,j1表示正面,j2表示底面

那么 dp[i][j2]=max{dp[i-1][j1]+1,dp[i][j2]} 每个立方体有两种状态用或者不用,通过颜色匹配来转移。

之前一度让我纠结的就是该如何输出过程也就是构造最优解。因为它是通过颜色来转移的,而且要求输出哪个面,而且对于每个立方体不是每种颜色都可以改变。因此让我很是纠结。后来过了一段时间重新做这个题,每次使用这个立方体的时候都记录下使用的是哪个面。然后递归输出最优解,如果dp[i][j2]=dp[i-1][j2]则表示没有使用第i个立方体,因此i变成i-1,重复判断。如果dp[i][j2]!=dp[i-1][j2],那肯定是使用了第i个立方体了,然后通过之前的记录数组找到是使用了哪个面,同时由面对应到第i-1个立方体底面的颜色。再递归直到层数为0即可。

 

rank跑了个85,还不错~

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define MAXN 100
using namespace std;
struct Cube
{
    int face[10];
};
int dp[505][105];
int note[505][105];
int n;
Cube p[505];
int getback(int a)
{
    if(a==1) return 2;
    if(a==2) return 1;
    if(a==3) return 4;
    if(a==4) return 3;
    if(a==5) return 6;
    if(a==6) return 5;
}
void PrintFace(int a,int b)
{
    printf("%d ",a);
    if(b==1)puts("front");
    else if(b==2) puts("back");
    else if(b==3) puts("left");
    else if(b==4) puts("right");
    else if(b==5) puts("top");
    else if(b==6) puts("bottom");
}
void OutPut(int i,int j,int ans)
{
    if(ans==0) return ;
    while(dp[i][j]==dp[i-1][j]&&i-1) i=i-1;
    int use=note[i][j];
    OutPut(i-1,p[i].face[use],ans-1);
    PrintFace(i,use);
}
int main()
{
    int kase=0;
    while(scanf("%d",&n)&&n)
    {
        memset(dp,0,sizeof(dp));
        memset(note,0,sizeof(note));
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=6; ++j)
                scanf("%d",&p[i].face[j]);
        for(int i=1; i<=n; ++i)
        {
            for(int j=1; j<=MAXN; ++j)
                dp[i][j]=dp[i-1][j];
            for(int j=1; j<=6; ++j)
            {
                int top=p[i].face[j],bak=p[i].face[getback(j)];
                if(dp[i-1][top]+1>dp[i][bak])
                {
                    dp[i][bak]=dp[i-1][top]+1;
                    note[i][bak]=j;
                }
            }
        }
        int ans=0,tt;
        for(int i=1; i<=MAXN; ++i)
            if(dp[n][i]>ans)
            {
                ans=dp[n][i];
                tt=i;
            }
        if(kase) printf("\n");
        printf("Case #%d\n",++kase);
        printf("%d\n",ans);
        OutPut(n,tt,ans);
    }
    return 0;
}


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值