【NOIP2009PJ】道路游戏 题解

题目

题目描述

          小新正在玩一个简单的电脑游戏。

          游戏中有一条环形马路,马路上有n 个机器人工厂,两个相邻机器人工厂之间由一小段 马路连接。小新以某个机器人工厂为起点,按顺时针顺序依次将这n 个机器人工厂编号为 1~n,因为马路是环形的,所以第n 个机器人工厂和第1 个机器人工厂是由一段马路连接在 一起的。小新将连接机器人工厂的这n 段马路也编号为1~n,并规定第i 段马路连接第i 个 机器人工厂和第i+1 个机器人工厂(1 ≤ i ≤ n-1),第n 段马路连接第n 个机器人工厂和第1 个机器人工厂。

          游戏过程中,每个单位时间内,每段马路上都会出现一些金币,金币的数量会随着时间 发生变化,即不同单位时间内同一段马路上出现的金币数量可能是不同的。小新需要机器人 的帮助才能收集到马路上的金币。所需的机器人必须在机器人工厂用一些金币来购买,机器 人一旦被购买,便会沿着环形马路按顺时针方向一直行走,在每个单位时间内行走一次,即 从当前所在的机器人工厂到达相邻的下一个机器人工厂,并将经过的马路上的所有金币收集 给小新,例如,小新在i(1 ≤ i ≤ n)号机器人工厂购买了一个机器人,这个机器人会从i 号 机器人工厂开始,顺时针在马路上行走,第一次行走会经过i 号马路,到达i+1 号机器人工 厂(如果i=n,机器人会到达第1 个机器人工厂),并将i 号马路上的所有金币收集给小新。

          游戏中,环形马路上不能同时存在2 个或者2 个以上的机器人,并且每个机器人最多能 够在环形马路上行走p 次。小新购买机器人的同时,需要给这个机器人设定行走次数,行走 次数可以为1~p 之间的任意整数。当马路上的机器人行走完规定的次数之后会自动消失,小 新必须立刻在任意一个机器人工厂中购买一个新的机器人,并给新的机器人设定新的行走次 数。

          以下是游戏的一些补充说明:

          1. 游戏从小新第一次购买机器人开始计时。

          2. 购买机器人和设定机器人的行走次数是瞬间完成的,不需要花费时间。

          3. 购买机器人和机器人行走是两个独立的过程,机器人行走时不能购买机器人,购买 完机器人并且设定机器人行走次数之后机器人才能行走。

          4. 在同一个机器人工厂购买机器人的花费是相同的,但是在不同机器人工厂购买机器 人的花费不一定相同。

          5. 购买机器人花费的金币,在游戏结束时再从小新收集的金币中扣除,所以在游戏过 程中小新不用担心因金币不足,无法购买机器人而导致游戏无法进行。也因为如此, 游戏结束后,收集的金币数量可能为负。

           现在已知每段马路上每个单位时间内出现的金币数量和在每个机器人工厂购买机器人 需要的花费,请你告诉小新,经过m 个单位时间后,扣除购买机器人的花费,小新最多能 收集到多少金币。

输入

          第一行 3 个正整数,n,m,p,意义如题目所述。

          接下来的 n 行,每行有m 个正整数,每两个整数之间用一个空格隔开,其中第i 行描 述了i 号马路上每个单位时间内出现的金币数量(1 ≤ 金币数量≤ 100),即第i 行的第j (1 ≤ j ≤m)个数表示第j 个单位时间内i 号马路上出现的金币数量。

          最后一行,有 n 个整数,每两个整数之间用一个空格隔开,其中第i 个数表示在i 号机 器人工厂购买机器人需要花费的金币数量(1 ≤ 金币数量≤ 100)。

输出

          共一行,包含1 个整数,表示在m 个单位时间内,扣除购买机器人 花费的金币之后,小新最多能收集到多少金币。

样例输入

2 3 2
1 2 3
2 3 4
1 2

样例输出

5

数据范围

40%:2 ≤ n ≤ 40,1 ≤m≤ 40。

90%:,2 ≤ n ≤ 200,1 ≤m≤ 200。

100%:2 ≤ n ≤ 1000,1 ≤m≤ 1000,1 ≤ p ≤m。

题目大意

        蜡笔小新可以从任意机器人工厂开始,他可以在停下来的时候花费b[j]的钱最多可以走p步。走的时候可以捡金币。问他最多捡到多少金币。

算法 

        这道题用动态规划。

        不要被它的数据范围所迷惑,实际上O(nmp)的算法能过。

        我们设f[i]表示前i个时间可以收集到的最大金币数。

        枚举时间i和起始点j,再枚举那个机器人走几步步到达的终点k。

        我们now表示到了几号机器人工厂,设累加器sum表示走k步可以捡的金币总量,那么小新可以从j走过来。则得到状态转移方程:

sum+=a[now][k];
f[k]=max(f[k],f[i-1]+sum-b[j]);

        最后输出f[m]即可。

注意事项

        开了long long会TLE。

代码

#include <cstdio>
using namespace std;
int max(int a,int b);

const int INF=0x7fffffff/3;
const int N=1005;
int a[N][N],b[N],f[N];

int main()
{
	int n,m,p,ans=0,sum=INF;
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d %d %d",&n,&m,&p);
	for (int i=1; i<=n; i++)
		for (int j=1; j<=m; j++) scanf("%d",&a[i][j]);
	for (int i=1; i<=n; i++) scanf("%d",&b[i]);
	for (int i=1; i<=m; i++)
		for (int j=1; j<=n; j++)
		{
			int now=j,sum=0;
			for (int k=i; k<=i+p-1 && k<=m; k++)
			{
				sum+=a[now][k];
				f[k]=max(f[k],f[i-1]+sum-b[j]);
				now++;
				if (now>n) now=1;
			}
		}
	printf("%d",f[m]);
	return 0;
} 
int max(int a,int b)
{
	if (a>b) return a;
	else return b;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值