zoukankan      html  css  js  c++  java
  • 【dp】10-15题解 snake vs block

    snake vs block

    题目描述

    Tgopknight最近迷上了一款叫做Snake vs Block的游戏,他总觉得他自己玩出的不是最优解,但是他忙于享受游戏的乐趣,只好请你帮忙找出最优解。

    Snake vs Block共有n5列的格子,每个格子上有砖块或者豆豆或者啥也没有,同行相邻格子 之间可能有挡板,砖块和豆豆有对应的数值,蛇的初始长度是4,在第1行第3列上,每吃一个豆豆可以增加相应长度,撞上一个砖块会减少相应长度,并且得到相应分数,蛇不能穿过挡板,长度小于零 即死亡(临死前撞的砖块不记得分),死亡或到达终点离开第n行)游戏结束。

    由于Tgopknight手速极快,他每前进到一行可以在这一行内任意移动,除非撞到挡板,他现在想知道他可以拿到的最高分是多少。

    输入输出

    input

    第一行输入一个正整数n,表示格子的行数

    后接n行,每行5个数,第i行第j个表示第i行第j列的格子,为ai,j,若ai,j<=0,则表示该格子上有个数 值为|ai,j|的砖块,若ai,j,则表示该格子上有个数值为ai,j的豆豆,若ai,j=0,则表示该格子上什么也没有

    第n+2行输入一个整数m,表示挡板的个数。

    后接m行,每行两个数x,y,表示第x行第y和第y+1列之间有挡板。

    output

    输出一行,一个正整数,为得到他能得到的最高分方案数

    样例

    input

    output

    数据范围

    对于30%的数据n < 5

    另有20%的数据m = 0

    另有20%的数据保证所有砖块所在的行数都比豆豆所在的行数大

    对于 100%的数据1 <= n < =200,-10 <=ai,j < =10,0 <= m <= min(n * 4, 200),1 <= x < =n,1 <=y <= 4

    数据保证第1行第3列上没有东西

    数据有梯度

    思路

    把豆豆和砖块丢在一起dp即可。

    令 f[i][j][k] 表示前i行,蛇的长度还剩下j,从第k列离开第i行的最大得分。

    令 g[j1][1][r] 表示蛇的长度还剩下j1,当前行在第1列到第r列之间移动后仍然未死亡的最大得分。

     f[0][4][3]=0 为初始状态。

    对于每个i,首先令 g[j1][k][k] = f[i - 1][j1 - a[i][k]][k]+max(-a[i][k],0) 为初始状态。

    状态转移方程为 g[j1][1][r] = max(g[j1-a[i][1]][1+1][r] +max(-a[i][j],0),g[j1-a[i][r]][1][r- 1] +max(-a[i][k], 0)) 

    最后 f[i][j][k] = max{g[j][1][r](1<= l <= k<= r <= 5)} 

            ans = max{f[i][j][k]} 

    具体做法参考std。

    时间复杂度o(n * (max(ai,j) * n) )

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int n, a[205][5],m,x,y,f[205][10005][5]={{{0}}};
    int g[10005][5][5] = {{{0}}}, maxi, ans = 0;
    bool flag[205][4] = {{false}};
    int main() {
    	freopen("snakevsblock.in","r",stdin);
    	freopen("snakevsblock.out","w",stdout);
    	scanf("%d",&n);
    	for (int i=1; i<=n; i++)
    		for (int j=0; j<5; j++)
    			scanf("%d",&a[i][j]);
    	scanf("%d", &m);
    	for (int i=1; i<=m; i++) {
    		scanf("%d%d", &x, &y);
    		flag[x][y-1] = true;   //设置挡板 
    	}
    	memset(f, -0x7f7f7f, sizeof(f));
    	f[0][4][2]=0;
    	maxi=n*50;
    	for(int i=1; i<=n;i++) {
    		memset(g,-0x7f7f7f, sizeof(g));
    		for (int j = 0; j<=maxi; j++)
    			for (int k =0; k<5; k++)
    				if (j-a[i][k]>= 0 && j-a[i][k]<=maxi)
    					f[i][j][k]=g[j][k][k]=f[i-1][j-a[i][k]][k]+max(-a[i][k], 0);    //初始化 
    		for (int l = 1; l <= 4; l++)
    			for (int j=0, k=j+l; k<5;j++,k++)
    				for (int v=0,val; v<=maxi; v++) {
    					/*挡板情况分类讨论*/ 
    					if (!flag[i][j] && (val=v-a[i][j]) >=0 && val<=maxi) g[v][j][k]=g[val][j+1][k]+max(-a[i][j],0);           
    					if (!flag[i][k-1] && (val=v-a[i][k])>=0&& val<=maxi) g[v][j][k]=max(g[v][j][k],g[val][j][k-1]+max(-a[i][k],0));
    					
    					for (int to = j; to <= k; to++) f[i][v][to]=max(f[i][v][to], g[v][j][k]);
    				}
    	}
    	for (int l=0;l<=n;l++)
    		for (int i=0; i<=maxi;i++)
    			for (int j=0;j<5;j++)
    				ans=max(ans,f[l][i][j]);
    	printf("%d
    ", ans);
    	return 0;
    }
    

      

     

  • 相关阅读:
    python基础:多进程讲解
    vue 导出数据
    vue 导入excel数据组件
    vue 分页组件
    vue 点击空白区域隐藏div
    vue 类似淘宝选择地址组件
    js基础练习经典题(数组,质数,数组的遍历等等)
    js去重复
    理解CSS3里的Flex布局用法
    书写HTML5/CSS3的命名规则
  • 原文地址:https://www.cnblogs.com/bbqub/p/7672654.html
Copyright © 2011-2022 走看看