ZCMU—1601

1601: 卡斯丁狗去挖矿

Time Limit: 3 Sec  Memory Limit: 128 MB
[Submit][Status][Web Board]

Description

 最近卡斯丁狗和他的好基友Tomcat在玩《我的世界》这款游戏。在游戏中玩家可以用各种材料搭建房屋,制造铁路线,制造炸弹,晚上还可以打僵尸等等。然而在这之前最最重要的就是挖矿。这天卡斯丁狗背着一个最多能装重量为 n 的背包去矿洞里挖矿。从洞口看矿洞是一个深度为d等腰RT超级赛亚三角形,每个坐标点都有矿(如图)。洞口在三角形的最顶端,坐标为(1,1)。由于卡斯丁狗开挂,他只想从坐标为(x,y)的点走到坐标为(x+1,y)或者(x+1,y+1)的点,并且每经过一个点他可以选着挖或者不挖这个点的矿。问卡斯丁狗最多能背多少矿回家。

Input

第一行输入n,d。

接下来d行第i行输入i个数,表示矿的重量。

输入为小于300大于0。

Output

 输出最大能带走的矿。

Sample Input

100 3
99
1 99
100 1 44

Sample Output

100

【分析】

本质上还是01背包....其实一眼就可以看出来的,只是在01背包的基础上增加了一个移动路径,所以给人一种需要bfs搜索路径后dp的错觉....当然bfs也是没问题的。
但其实...不用考虑那么多三维dp直接做就可以了,因为数据不大只有300 ,  300*300*300*4/1024/1024≈102MB
所以直接干就行了...
f[i][j][k]表示到坐标(i,j)背包使用量为k时的最大价值,对于矿石,价格和体积都是a[i][j]
那么当前状态可以从f[i-1][j][k],f[i-1][j-1][k],f[i-1][j][k-a[i][j]],f[i-1][j-1][k-a[i][j]]四个状态移动过来
状态转移方程:f[i][j][k]=max(max(f[i-1][j][k],f[i-1][j-1][k]),max(f[i-1][j][k-a[i][j]]+a[i][j],f[i-1][j-1][k-a[i][j]]+a[i][j]));
显然方程虽然长,但是并没有什么特殊的地方... 就是一个三维的01背包...多了一个坐标限制条件罢了,因为限制了坐标,所以无所谓k正着还是反着~
(PS.这里我为了省内存所以没有读取a[i][j],因为a[i][j]的时效性只有一次,所以重复读取进一个变量也可以)
【代码】
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int f[310][310][310];

int main()
{
	int n,m,x;
	while (~scanf("%d%d",&m,&n))
	{
		memset(f,0,sizeof(f));
		int ans=0;
		//for (int i=1;i<=n;i++) for (int j=1;j<=i;j++) scanf("%d",&a[i][j]);
		for (int i=1;i<=n;i++)
			for (int j=1;j<=i;j++)
			{
				scanf("%d",&x);
				for (int k=x;k<=m;k++)
				{
					f[i][j][k]=max(max(f[i-1][j][k],f[i-1][j-1][k]),max(f[i-1][j][k-x]+x,f[i-1][j-1][k-x]+x));
					ans=max(ans,f[i][j][k]);
				}		
			}
		printf("%d\n",ans);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值