#(技巧型DP)洛谷P1070 道路游戏(提高+/省选-)

题目描述

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

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

游戏过程中,每个单位时间内,每段马路上都会出现一些金币,金币的数量会随着时间发生变化,即不同单位时间内同一段马路上出现的金币数量可能是不同的。小新需要机器人的帮助才能收集到马路上的金币。所需的机器人必须在机器人工厂用一些金币来购买,机器人一旦被购买,便会沿着环形马路按顺时针方向一直行走,在每个单位时间内行走一次,即从当前所在的机器人工厂到达相邻的下一个机器人工厂,并将经过的马路上的所有金币收集给小新,例如,小新在ii(1≤i≤n1in)号机器人工厂购买了一个机器人,这个机器人会从 ii 号机器人工厂开始,顺时针在马路上行走,第一次行走会经过ii号马路,到达 i+1i+1号机器人工厂(如果 i=ni=n,机器人会到达第11 个机器人工厂),并将ii 号马路上的所有金币收集给小新。 游戏中,环形马路上不能同时存在22个或者 22个以上的机器人,并且每个机器人最多能够在环形马路上行走pp次。小新购买机器人的同时,需要给这个机器人设定行走次数,行走次数可以为 1~p1 p 之间的任意整数。当马路上的机器人行走完规定的次数之后会自动消失,小新必须立刻在任意一个机器人工厂中购买一个新的机器人,并给新的机器人设定新的行走次数。

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

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

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

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

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

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

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

输入格式

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

接下来的nn行,每行有 mm 个正整数,每两个整数之间用一个空格隔开,其中第 i 行描

述了 ii 号马路上每个单位时间内出现的金币数量(1≤1≤金币数量≤100100),即第 ii行的第 jj(1≤j≤m1jm)个数表示第 jj 个单位时间内 i 号马路上出现的金币数量。

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

输出格式

共一行,包含11个整数,表示在mm 个单位时间内,扣除购买机器人

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

输入输出样例

输入 #1复制
2 3 2 
1 2 3 
2 3 4 
1 2
输出 #1复制
5

说明/提示

【数据范围】

对于 40%的数据,2≤n≤40,1≤m≤402n40,1m40。

对于 90%的数据,2≤n≤200,1≤m≤2002n200,1m200。

对于 100%的数据,2≤n≤1000,1≤m≤1000,1≤p≤m2n1000,1m1000,1pm。

NOIP 2009 普及组 第四题

分析:考虑要得到最大的金币:对于这个环,首先破开来考虑,把他变成一个长度为2*n的序列;

考虑状态的维护方法:首先,要维护一个位置坐标,即当前在哪一个机器人工厂;

其次,要维护当前的时间。然后还要存储金币的数目;还有机器人的步数p

所以设dp[i][j]表示在i时间到达j工厂的最大金币数目;

对于dp[i][j],它可以是由前1-p个工厂转移过来的!

即:dp[i][j]=max(dp[i-1][j-1],dp[i-2][j-2],dp[i-3][j-3],...dp[i-p][j-p])+money[i][j];

然后考虑初始化:dp[1][j]=money[j][1]-cost[j];

其余初始化为0;

(Error !)

正解:https://www.luogu.org/problemnew/solution/P1070

 

/*
1.对于f[i][j],设其为第i时间到达j处的最大金币数;
r[i][j]表示第j个时刻到达第i个工厂的价值;
sum[i][j]表示价值的前缀和,也就是在j时刻到达i工厂的金币数之和!
因为存在时间和工厂两个约束量,需要使用二维前缀和!
sum[i][j]-sum[i-1][j-1]=r[i][j];
那么,其实每次读入,维护的前缀和都是更新同一对角线上的sum数组!
所以对于:sum[i][j]-sum[i-k][j-k]等价于:r[i-k+1][j-k+1]+r[i-k+2][j-k+2]
+....+r[i][j];也就是:在j-k时刻走到i-k工厂后,再走k个时刻,走t分钟的话
那么当前对应的价值应为r[i-k+t][j-k+t];
等价于存储了从j-k时刻开始从i-k处开始走,等到k个时间后,走到i处,
所能获得的最大价值!

*/
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,p;
int sum[1002][1002],r[1002][1002],cost[1002],dp[1002];
inline int max(int x,int y)
{
return x>y?x:y;
}
inline int read()
{
char ch;
while((ch=getchar())<'0' || ch>'9');
int res=ch-'0';
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-'0';
return res;
}
int main()
{
int t;
n=read(),m=read(),p=read();
for(int i=1;i<=n;i++)//读入第i条道路在第j个时刻的金币数目!
for(int j=1;j<=m;j++)//定义第i条道路连接i和i+1,若i=n,则连接n->1;
{
scanf("%d",&r[i][j]);//
}
for(int i=1;i<=n;i++)//读入每个工厂制造机器人的消耗
scanf("%d",&cost[i]);//
for(int i=1;i<=m;i++)//初始化dp[i]数组为极小值
{//
dp[i]=-1e9;//
}
int ans;//ans存储第i个时刻结束,在j工厂处购买的最大金币数目
for(int i=1;i<=m;i++)//
for(int j=1;j<=n;j++)//
{
ans=-cost[j]+dp[i-1];//dp[i-1]为上一刻的max价值,一定满足最优子结构性质
for(int k=0;k<p&&i+k<=m;k++)//对所有的走法进行dp
{
t=j+k>n?(j+k)%n:j+k;//对环的情况进行处理
ans+=r[t][i+k];//加上i+k时刻走到t的价值
dp[i+k]=max(dp[i+k],ans);//获取最大价值!
}
}
printf("%d",dp[m]);//输出最大价值!
return 0;
}

 

转载于:https://www.cnblogs.com/little-cute-hjr/p/11440588.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值