题意:有 n n n层 4 ∗ 4 4*4 4∗4的格子,每个格子有一个权值,你要从第 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;
}