「NOIP模擬」【2018.11.6晚間訓練賽】Snake vs Block【動態規劃】

題目描述

TgopknightTgopknight最近迷上了一款叫做Snake vs BlockSnake\ vs\ Block的遊戲,他總覺得自己玩出的不是最優解,但是他忙於享受遊戲的樂趣,只好請你幫忙找出最優解。
在這裏插入圖片描述

Snake vs BlockSnake\ vs\ Block共有nn55列的格子,每個格子上有磚塊或者豆豆或者啥也沒有,同行相鄰格子之間可能有擋板,磚塊和豆豆有對應的數值,蛇的初始長度是44,在第11行第33列上,每吃一個豆豆可以增加相應長度,撞上一個磚塊會減少相應長度,並且得到相應分數,蛇不能穿過擋板,長度小於零即死亡(臨死前撞的磚塊不記得分),死亡或到達終點(離開第nn行)遊戲結束。

由於TgopknightTgopknight手速極快,他每前進到一行可以在這一行內任意移動,除非撞到擋板,他現在想知道他可以拿到的最高分是多少。


做法來源於oioi同仁FancyDesignFancyDesign

f[x][s][len]f[x][s][len]表示已經走到了第xx層,其中在第ii層行走的路徑狀態爲ss,並且此時蛇的長度爲lenlen

其中,ss的二進制狀態是唯一連續的一段。

考慮左右移動,得到新的狀態:f[x][s(1<<(i1)][len]f[x][s|(1<<(i-1)][len']

其中,ii是與ss相鄰的一個格點位置,lenlen'是移動後對應的長度。

考慮向下移動,得到新的狀態:f[x+1][1<<(i1)][len]f[x+1][1<<(i-1)][len']

其中,isi∈slenlen'同上。

另外,由於ff的空間消耗以及超過了限制,但是注意到ff的數據範圍始終很小,所以可以類型shortshort節省一下空間。

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章