1171. Lost in Space

题意:有 n n n 4 ∗ 4 4*4 44的格子,每个格子有一个权值,你要从第 1 1 1层的起点走到第 n n n层的任意一个点,每一从只有一些格子能去到下一层,每个格子不能重复经过,求最大的平均权值。

Solution

这道题看起来不算难,但做起来会发现挺恶心的,卡空间卡得特别厉害。
我花了差不多一个上午的时间AC这一道题。

为了节省数组的空间,我们先处理每一层的内部,因为路径的条数十分有限,我们可以直接用暴力来处理。定义 f [ f l o o r ] [ x 1 ] [ y 1 ] [ x 2 ] [ y 2 ] [ k ] f[floor][x_1][y_1][x_2][y_2][k] f[floor][x1][y1][x2][y2][k]表示在 f l o o r floor floor ( x 1 , y 1 ) (x_1,y_1) (x1,y1)为起点, ( x 2 , y 2 ) (x_2,y_2) (x2,y2)为终点走过 k k k个房间的最大权值和。

然后考虑层与层之间的关系,令 d p [ f l o o r ] [ x ] [ y ] [ k ] dp[floor][x][y][k] dp[floor][x][y][k]表示在 f l o o r floor floor ( x , y ) (x,y) (x,y)这个位置一共经过 k k k个房间的最大权值数,然后用 p r e [ f l o o r ] [ x ] [ y ] [ k ] pre[floor][x][y][k] pre[floor][x][y][k]来记录这一层的起点。最后再用和处理每一层一样的方法来寻找一下路径就可以了。

Code

#include<bits/stdc++.h>
#define ll long long
#define gc getchar
#define pc putchar
#define pii pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define dwn(i,x,y) for(int i=x;i>=y;i--)
#define mod 1000000007
using namespace std;
template<typename T>inline void qr(T &x){
  x=0;int f=0;char s=gc();
  while(s<'0'||'9'<s)f|=s=='-',s=gc();
  while('0'<=s&&s<='9')x=x*10+s-48,s=gc();
  x=f?-x:x;
}
int cc=0,buf[31];
template<typename T>inline void qw(T x){
  if(x<0)putchar('-'),x=-x;
  do{buf[++cc]=int(x%10);x/=10;}while(x);
  while(cc)pc(buf[cc--]+'0');puts("");
}
int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
int mu(int x,int y){return 1ll*x*y%mod;}
int de(int x,int y){return (x-y)<0?x-y+mod:x-y;}
const int N=17;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
const char dc[4]={'N','S','W','E'};
int n,a[N][4][4],f[N][4][4][4][4][N];bool bk[N][4][4],v[4][4];
int fl,stx,sty,dp[N][4][4][N*N],edx,edy,edk;
struct node{int x,y,k;}pre[N][4][4][N*N];
int inf;string path="";
void dfs(int x,int y,int tot,int sum){
  v[x][y]=1;
  if(f[fl][stx][sty][x][y][tot]<sum)
    f[fl][stx][sty][x][y][tot]=sum;
  for(int i=0;i<4;i++){
    int xx=x+dx[i],yy=y+dy[i];
    if(xx<0||xx>3||yy<0||yy>3)continue;
    if(!v[xx][yy])dfs(xx,yy,tot+1,sum+a[fl][xx][yy]);
  }
  v[x][y]=0;
}
bool dfs3(int x,int y,int tot,int sum,string now){
  if(x==edx&&y==edy&&tot==edk&&f[fl][stx][sty][edx][edy][edk]==sum){
    path+=now;
    return 1;
  }
  v[x][y]=1;
  for(int i=0;i<4;i++){
    int xx=x+dx[i],yy=y+dy[i];
    if(xx<0||xx>3||yy<0||yy>3)continue;
    if(!v[xx][yy]){
      if(dfs3(xx,yy,tot+1,sum+a[fl][xx][yy],now+dc[i])){v[x][y]=0;return 1;}
    }
  }
  v[x][y]=0;
  return 0;
}
void dfs2(int p,int x,int y,int k){
  if(p!=1){
    dfs2(p-1,pre[p][x][y][k].x,pre[p][x][y][k].y,k-pre[p][x][y][k].k);
    path+='D';
  }
  edx=x,edy=y,edk=pre[p][x][y][k].k;
  stx=pre[p][x][y][k].x;
  sty=pre[p][x][y][k].y;
  fl=p;dfs3(stx,sty,1,a[p][stx][sty],"");
}
int main(){
  qr(n);
  rep(k,1,n){
    rep(i,0,3)rep(j,0,3)qr(a[k][i][j]);
    rep(i,0,3)rep(j,0,3){int x;qr(x);bk[k][i][j]=x;}
  }
  rep(i,0,3)rep(j,0,3)bk[n][i][j]=1;
  pii st;qr(st.fi),qr(st.se);st.fi--,st.se--;
  memset(f,-63,sizeof(f));inf=f[0][0][0][0][0][0];
  bk[0][st.fi][st.se]=1;
  rep(i,1,n){
    fl=i;
    for(stx=0;stx<4;stx++)
      for(sty=0;sty<4;sty++)
        if(bk[i-1][stx][sty])
          dfs(stx,sty,1,a[i][stx][sty]);
  }
  memset(dp,-63,sizeof(dp));dp[0][st.fi][st.se][0]=0;
  rep(i,1,n)
    rep(x1,0,3)rep(y1,0,3)if(bk[i-1][x1][y1])
      rep(x2,0,3)rep(y2,0,3)if(bk[i][x2][y2])
        rep(j,1,16)if(f[i][x1][y1][x2][y2][j]!=inf)
          rep(k,0,256-j)if(dp[i-1][x1][y1][k]!=inf)
            if(dp[i][x2][y2][k+j]<dp[i-1][x1][y1][k]+f[i][x1][y1][x2][y2][j]){
              dp[i][x2][y2][k+j]=dp[i-1][x1][y1][k]+f[i][x1][y1][x2][y2][j];
              pre[i][x2][y2][k+j]=(node){x1,y1,j};
            }
  double ans=-1;int ax,ay,ak;
  rep(k,1,256)rep(i,0,3)rep(j,0,3)if(ans<1.0*dp[n][i][j][k]/k){
    ans=1.0*dp[n][i][j][k]/k;
    ax=i,ay=j,ak=k;
  }
  dfs2(n,ax,ay,ak);
  printf("%.4lf\n%d\n",ans,path.size());
  cout<<path<<endl;
  return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值