ural 1171 DFS+DP

反思:想到分层,但没有发现其DP的本质;单层预处理能又没用dfs实现导致错误;输出路径更是完全没头绪。。

//代码一
//DP时从上到下(第n层到第一层)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#define N 260
using namespace std;
int a[17][4][4],b[17][4][4],n;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
bool p[4][4];
int vis[17][4][4];
int pre[17][4][4];
int len[17][N][4][4];
int pre2[17][N][4][4];
int    f[17][N][4][4];
char fan[4]={'N','S','W','E'};
string anss;
int food,path,nn,d,x,y;
void dfs(int step,int x,int y,int d)
{
    food+=a[nn][x][y];
    path<<=2; path+=d; p[x][y]=1;
    if (food>vis[step][x][y])
        {
            vis[step][x][y]=food;
            pre[step][x][y]=path;
        }
    for (int k=0;k<4;k++)
        {   int nx=x+dx[k],ny=y+dy[k];
            if (nx<0||nx>=4) continue;
            if (ny<0||ny>=4) continue;
            if (p[nx][ny]) continue;
            dfs(step+1,nx,ny,k);
        }
    food-=a[nn][x][y];
    path>>=2; p[x][y]=0;
}

void dp(int i,int j)
{
    for (int x=0;x<4;x++)
    for (int y=0;y<4;y++)
    for (int d=1;d<=16;d++)
    for (int st=n+1-nn;st<=((n+1-nn)<<4);st++)
        if (st>=d)
             if (     (f[nn+1][st-d][i][j]||nn==n)
                    &&(vis[d][x][y])
                    &&(f[nn+1][st-d][i][j]+vis[d][x][y]>f[nn][st][x][y])
                )
                {      f[nn][st][x][y]=f[nn+1][st-d][i][j]+vis[d][x][y];
                     len[nn][st][x][y]=d-1;
                    pre2[nn][st][x][y]=pre[d][x][y];
                }
}

string esolve(int len,int pp)
{
    string re;
    re="";
    for (int i=1;i<=len;i++)
         {   re=fan[pp&3]+re;
             pp>>=2;
         }
    return re;
}

void solve(int k)
{   string re=esolve(len[k][d][x][y],pre2[k][d][x][y]);
    anss=re+anss;
    if (k==n){ return;}
    int len=re.length();
    for (int i=0;i<len;i++)
        {if (re[i]=='W') y++;
         if (re[i]=='E') y--;
         if (re[i]=='N') x++;
         if (re[i]=='S') x--;
        }
    anss='D'+anss;
    d-=(len+1);
}
void doit()
{   for (int i=n;i>=1;i--)
    { for (int j=0;j<4;j++)
      for (int k=0;k<4;k++)
        scanf("%d",&a[i][j][k]);
      for (int j=0;j<4;j++)
      for (int k=0;k<4;k++)
        scanf("%d",&b[i][j][k]);
    }
    memset(f,0,sizeof(f));
    scanf("%d%d",&x,&y);
    x--;y--;

    b[n+1][x][y]=1;
    for (nn=n;nn>=1;nn--)
    for (int i=0;i<4;i++)
    for (int j=0;j<4;j++)
        if (b[nn+1][i][j])
            {   memset(vis,0,sizeof(vis));
                memset(p,0,sizeof(p));
                food=0; path=0;
                dfs(1,i,j,0);
                dp(i,j);
            }

    double ans=0;
    d=0;
    for (int i=0;i<4;i++)
    for (int j=0;j<4;j++)
    for (int k=n;k<=(n<<4);k++)
        if (double(f[1][k][i][j])/k>ans)
            {
                ans=double(f[1][k][i][j])/k;
                d=k;
                x=i;
                y=j;
            }
    printf("%.4lf\n%d\n",ans,d-1);
    anss="";

    for (int i=1;i<=n;i++)
    solve(i);
    cout<<anss<<endl;
}
int main()
{
    while (scanf("%d",&n)!=EOF) doit();
}


//代码二
//DP时从下到上(第一层到第n层)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
#define N 260
using namespace std;
int a[17][4][4],b[17][4][4],n;
int dx[4]={-1,1,0,0};
int dy[4]={0,0,-1,1};
bool p[4][4];
int vis[17][4][4];
int pre[17][4][4];
int len[17][N][4][4];
int pre2[17][N][4][4];
int    f[17][N][4][4];
char fan[4]={'S','N','E','W'};

int food,path,nn,d,x,y;
void dfs(int step,int x,int y,int d)
{   food+=a[nn][x][y];
    path<<=2; path+=d; p[x][y]=1;
    if (food>vis[step][x][y])
        {   vis[step][x][y]=food;
            pre[step][x][y]=path;
        }
    for (int k=0;k<4;k++)
        {   int nx=x+dx[k],ny=y+dy[k];
            if (nx<0||nx>=4) continue;
            if (ny<0||ny>=4) continue;
            if (p[nx][ny]) continue;
            dfs(step+1,nx,ny,k);
        }
    food-=a[nn][x][y];
    path>>=2; p[x][y]=0;
}

void dp(int i,int j)
{   for (int x=0;x<4;x++)
    for (int y=0;y<4;y++)
    for (int d=1;d<=16;d++)
    for (int st=nn;st<=(nn<<4);st++)
        if (st>=d)
             if (     (nn==1||f[nn-1][st-d][i][j])
                    &&(vis[d][x][y])
                    &&(f[nn-1][st-d][i][j]+vis[d][x][y]>f[nn][st][x][y])
                )
                {      f[nn][st][x][y]=f[nn-1][st-d][i][j]+vis[d][x][y];
                     len[nn][st][x][y]=d-1;
                    pre2[nn][st][x][y]=pre[d][x][y];
                }
}

string esolve(int len,int pp)
{
    string re;
    re="";
    for (int i=1;i<=len;i++)
         {   re=re+fan[pp&3];
             pp>>=2;
         }
    return re;
}

void solve(int k)
{   string re=esolve(len[k][d][x][y],pre2[k][d][x][y]);
    cout<<re;
    if (k==1){cout<<endl; return;}
    int len=re.length();
    for (int i=0;i<len;i++)
        {if (re[i]=='W') y--;
         if (re[i]=='E') y++;
         if (re[i]=='N') x--;
         if (re[i]=='S') x++;
        }
    cout<<'D';
    d-=(len+1);
}
void doit()
{   for (int i=n;i>=1;i--)
    { for (int j=0;j<4;j++)
      for (int k=0;k<4;k++)
        scanf("%d",&a[i][j][k]);
      for (int j=0;j<4;j++)
      for (int k=0;k<4;k++)
        scanf("%d",&b[i][j][k]);
    }
    for (int j=0;j<4;j++)
    for (int k=0;k<4;k++)
        b[1][j][k]=1;

    memset(f,0,sizeof(f));
    for (nn=1;nn<=n;nn++)
    for (int i=0;i<4;i++)
    for (int j=0;j<4;j++)
        if (b[nn][i][j])
            {   memset(vis,0,sizeof(vis));
                memset(p,0,sizeof(p));
                food=0; path=0;
                dfs(1,i,j,0);
                dp(i,j);
            }
    scanf("%d%d",&x,&y);
    x--;y--;
    double ans=0;
    d=0;
    for (int k=n;k<=(n<<4);k++)
        if (double(f[n][k][x][y])/k>ans)
            {
                ans=double(f[n][k][x][y])/k;
                d=k;
            }
    printf("%.4lf\n%d\n",ans,d-1);
    for (int i=n;i>=1;i--)
        solve(i);

}
int main()
{
    while (scanf("%d",&n)!=EOF) doit();
}

无论哪种方向,最后输出路径方向一定与dp方向相反

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值