題目描述
最近迷上了一款叫做的遊戲,他總覺得自己玩出的不是最優解,但是他忙於享受遊戲的樂趣,只好請你幫忙找出最優解。
共有行列的格子,每個格子上有磚塊或者豆豆或者啥也沒有,同行相鄰格子之間可能有擋板,磚塊和豆豆有對應的數值,蛇的初始長度是,在第行第列上,每吃一個豆豆可以增加相應長度,撞上一個磚塊會減少相應長度,並且得到相應分數,蛇不能穿過擋板,長度小於零即死亡(臨死前撞的磚塊不記得分),死亡或到達終點(離開第行)遊戲結束。
由於手速極快,他每前進到一行可以在這一行內任意移動,除非撞到擋板,他現在想知道他可以拿到的最高分是多少。
做法來源於同仁
表示已經走到了第層,其中在第層行走的路徑狀態爲,並且此時蛇的長度爲。
其中,的二進制狀態是唯一連續的一段。
考慮左右移動,得到新的狀態:
其中,是與相鄰的一個格點位置,是移動後對應的長度。
考慮向下移動,得到新的狀態:
其中,,同上。
另外,由於的空間消耗以及超過了限制,但是注意到的數據範圍始終很小,所以可以類型節省一下空間。
#include <bits/stdc++.h>
using namespace std;
short f[205][32][10005];
int n,m,a[205][6],lim[205][6];
int dfs(int x,int s,int len) {
if(x>n) return 0;
if(f[x][s][len]!=-1) return f[x][s][len];
int ret=0;
for(int i=1;i<=5;i++) if(!((1<<(i-1))&s)) if((((1<<i)&s)&&(!lim[x][i]))||(i>1&&((1<<(i-2))&s)&&(!lim[x][i-1]))) {
if(a[x][i]>=0) ret=max(ret,dfs(x,s|(1<<(i-1)),len+a[x][i]));
else if(a[x][i]+len>=0) ret=max(ret,dfs(x,s|(1<<(i-1)),len+a[x][i])+abs(a[x][i]));
}//左右轉移
for(int i=1;i<=5;i++) if((1<<(i-1))&s) {
if(a[x+1][i]>=0) ret=max(ret,dfs(x+1,1<<(i-1),len+a[x+1][i]));
else if(len+a[x+1][i]>=0) ret=max(ret,abs(a[x+1][i])+dfs(x+1,1<<(i-1),len+a[x+1][i]));
}//往下面一層走
return f[x][s][len]=ret;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) for(int j=1;j<=5;j++) scanf("%d",&a[i][j]);
scanf("%d",&m);
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);lim[x][y]=1;
}
memset(f,-1,sizeof(f));
printf("%d\n",dfs(1,4,4));
return 0;
}