您的位置:首页 > 其它

noip2009普及组道路游戏解题报告

2014-12-26 16:16 295 查看
原题:

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

  游戏中有一条环形马路,马路上有 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 个单位时间内,扣除购买机器人

花费的金币之后,小新最多能收集到多少金币。

分析:

如果用f[i][j][step]来记录第i时刻在位置j走了step步的机器人能获得的最多金币数。那么这道题不难,不过很显然会超时,那么我们能不能想到一种能压缩维度的方法呢?现在我们用f[i][j]表示第i时间,在第j位置能获得的最多金币数,coin[i][j]
在i马路上,时间j的金币数。step[i][j]
表示在 第i时间,第j个工厂前的机器人已经走的步数。好了问题来了?你觉得什么时候f[i][j]能取得最大值呢?因为机器人是从j的前一个位置走过来的,显然在j的前一位置会发生两种情况:

(1)买机器人

什么时候会需要买机器人?两种情况,第一种情况,就是在j的前一位置已经走了P步了,那么肯定需要买机器人了。第二种情况,就是在第i-1秒的时候存在某个位置其获得的金币数减去在j的前一个工厂购买机器人花费的金币数还比在第i-1秒在j的前一位置获得的金币多,那么说明j的前一位置在第i-1秒即使不买机器人,直接走过来也比不上我从取得最大值的位置直接回收机器人再从j的前一位置直接走过来获得的金币多。两种情况谁先考虑谁后考虑?不重要,你会发觉他们的求法是一样的。

(2)不买机器人

不买机器人就很简单了,除了(1)的情况就是(2)的情况,该有的处理也不多:步数加1,然后加上从j的前一位置走到j位置获得的金币数即可。

#include <iostream>
#include<cstdio>
using namespace std;
int f[1010][1010];//f[i][j]表示第i时间,在第j位置能获得的最后金币数
int coin[1010][1010];//coin[i][j]  在i马路上,时间j的金币数
int cost[1010];
int circlePre[1010];
int step[1010][1010];//step[i][j]  第i时间,第j个工厂前的机器人已经走的步数
int main(int argc, const char * argv[]) {
int n,m,p,i,j;
while (scanf("%d%d%d",&n,&m,&p)!=EOF) {
for (i=1; i<=n; i++) {
for (j=1; j<=m; j++) {
scanf("%d",&coin[i][j]);
}
}
scanf("%d",&cost[1]);
circlePre[1]=n;
for (i=2; i<=n; i++) {
scanf("%d",&cost[i]);
circlePre[i]=i-1;
}
int maxvalue=-1<<28;
int pastMaxValue=-1<<28;
for (i=1; i<=n; i++) {
step[1][i]=1;
f[1][i]=coin[circlePre[i]][1]-cost[circlePre[i]];
if (maxvalue<f[1][i]) {
maxvalue=f[1][i];
}
}
pastMaxValue=maxvalue;
for (i=2; i<=m; i++) {
maxvalue=-1<<28;
for (j=1; j<=n; j++) {
if ((step[i-1][circlePre[j]]<p)&&((pastMaxValue-cost[circlePre[j]]<f[i-1][circlePre[j]])))
{
step[i][j]=step[i-1][circlePre[j]]+1;
f[i][j]=f[i-1][circlePre[j]]+coin[circlePre[j]][i];
}
else{
step[i][j]=1;
f[i][j]=pastMaxValue-cost[circlePre[j]]+coin[circlePre[j]][i];
}
if (f[i][j]>maxvalue) {
maxvalue=f[i][j];
}
}
pastMaxValue=maxvalue;
}
printf("%d\n",maxvalue);
}
return 0;
}


PS:在这里我也说下两个我自己对这道题的看法。第一,上面的代码虽然能AC掉,但我觉得其实还有漏洞,我觉得应该还存在某个时刻不走的情况,上面代码没体现。第二,我觉得在买机器人的情况的第二种情况,就是在第i-1秒的时候存在某个位置其获得的金币数减去在j的前一个工厂购买机器人花费的金币数还比在第i-1秒在j的前一位置获得的金币多,这个细节上,我觉得等于也应该置1,因为他能保持更少的步数但具有相同的值。

好了,就这么多,这是我写的第一篇关于noip的博文吧?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: