记忆化搜索(跳舞机,uva 10618)

今天写了好久都没写出来,后来看别人代码才过了。

刚开始写的时候,觉得决策十分复杂,一直在讨论,写了很长。后来打印决策的时候遇到了更大的麻烦,只好用dfs递归去打印。代码长到爆炸,而且还WA了。

后来看别人代码,学到几个技巧。

在dp时直接暴力枚举所有决策,然后写一个函数判断是否合法即可。

能量消耗也不需要在dp时判断,直接交给函数处理就好了。

最开始之所以WA是因为路径保存错了。我只保存了一维的路径,其实要保存四维的路径,这样才能保证记录了所有状态的下一个状态,下一个状态用结构体表示。


代码

#include<bits/stdc++.h>
#define INF 0X3F3F3F3F
using namespace std;

struct Node
{
    int l,r,s;
}path[80][5][5][5];
char str[80];
int dp[80][5][5][5];
int len;

int ok(int l,int r,int nl,int nr)
{
    if(l==nl&&r==nr) return 1;
    else if(l==nl) return (nr!=l&&l!=2);
    else if(r==nr) return (nl!=r&&r!=4);
    else return 0;
}

int cost(int f,int t,int last,int now)
{
    if(last!=now) return 1;
    else if(f==t) return 3;
    else if((f+t)%2) return 5;
    else return 7;
}

int dfs(int i,int a,int b,int s)
{
    if(i==len) return 0;
    int& ans=dp[i][a][b][s];
    Node& p=path[i][a][b][s];
    if(ans>=0) return ans;
    ans=INF;
    if(str[i]=='.')
    {
        ans=min(ans,dfs(i+1,a,b,0));
        p.l=a,p.r=b,p.s=0;
        for(int j=1;j<=4;j++)
        {
            if(ok(a,b,j,b))
            {
                int temp=dfs(i+1,j,b,1)+cost(a,j,s,1);
                if(temp<ans)
                {
                    ans=temp;
                    p.l=j,p.r=b,p.s=1;
                }
            }
            if(ok(a,b,a,j))
            {
                int temp=dfs(i+1,a,j,2)+cost(b,j,s,2);
                if(temp<ans)
                {
                    ans=temp;
                    p.l=a,p.r=j,p.s=2;
                }
            }
        }
    }
    else
    {
        int pos;
        switch (str[i])
        {
            case 'U':pos=1;break;
            case 'D':pos=3;break;
            case 'L':pos=4;break;
            case 'R':pos=2;break;
        }
        if(ok(a,b,pos,b))
        {
            int temp=dfs(i+1,pos,b,1)+cost(a,pos,s,1);
            if(temp<ans)
            {
                ans=temp;
                p.l=pos,p.r=b,p.s=1;
            }
        }
        if(ok(a,b,a,pos))
        {
            int temp=dfs(i+1,a,pos,2)+cost(b,pos,s,2);
            if(temp<ans)
            {
                ans=temp;
                p.l=a,p.r=pos,p.s=2;
            }
        }
    }
    return ans;
}

void print()
{
    int la=4,lb=2,ls=0;
    int a=path[0][la][lb][ls].l;
    int b=path[0][la][lb][ls].r;
    int s=path[0][la][lb][ls].s;
    for(int j=1;j<=len;j++)
    {
        if(s==0) printf(".");
        else if(s==1) printf("L");
        else printf("R");
        la=a;
        lb=b;
        ls=s;
        a=path[j][la][lb][ls].l;
        b=path[j][la][lb][ls].r;
        s=path[j][la][lb][ls].s;
    }
    puts("");
}

int main()
{
    while(1)
    {
        scanf("%s",str);
        if(str[0]=='#') break;
        len=strlen(str);
        memset(dp,-1,sizeof(dp));
        dfs(0,4,2,0);
        print();
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值