【线性DP】跳格子问题 + 光签题(取石子游戏)
Part1跳格子Part\ 1\ 跳格子Part 1 跳格子
LDUOJ 测试平台传送门
问题描述:
NikolaNikolaNikola 现在已经成为一个游戏里的重要人物。这个游戏是由一行 NNN 个方格,NNN 个方格用 111 到 NNN 的数字表示。
NikolaNikolaNikola 开始是在 111 号位置,然后能够跳到其他的位置,NikolaNikolaNikola 的第一跳必须跳到 222 号位置。随后的每一跳必须满足两个条件:
- 如果是向前跳,必须比前面一跳远一个方格。
- 如果是向后跳,必须和前面一跳一样远。
比如,在第一跳之后(当在 222 号位置时),NikolaNikolaNikola 能够跳回 111 号位置,或者向前跳到 444 号位置。
每次他跳入一个位置,NikolaNikolaNikola 必须付费。NikolaNikolaNikola 的目标是从 111 号位置尽可能便宜地跳到 NNN 号位置。
写一个程序,看看 NikolaNikolaNikola 跳到 NNN 号位置时最小的花费。
输入:
输入文件 nikola.innikola.innikola.in 共有 N+1N+1N+1 行。
第一行:包含一个整数NNN,2≤N≤10002≤N≤10002≤N≤1000,它是位置的编号。
第2..N+12..N+12..N+1行:第i+1i+1i+1行表示第 iii 个方格的费用,是一个正整数,绝对不超过 500500500。
输出:
输出文件 nikola.outnikola.outnikola.out 中只有一个数,表示 NikolaNikolaNikola 跳到 NNN 号位置时最小的花费。
解题思路:
首先,我们需要确定的是所求答案所在的状态。对于所到达的每一个格子,要么从左边的某一个格子跳过来,要么从右边的某一个格子跳过来。按这种划分方式将所有方案划分成各个集合。我们可以用 f[i][j]f[i][j]f[i][j] 来表示每一个集合。f[i][j]f[i][j]f[i][j] 表示从第 jjj 个格子跳到第 iii 个格子的最小花费。
状态转移:
1、
if (j - i >= 1) f[j][i] = min(f[j][i], f[j - i][i - 1] + a[j]);
2、
if(i + j <= n) f[j][i] = min(f[j][i], f[j + i][i] + a[j]);
从状态转移方程式中可以看出,转移的方式是由已知的当前状态去更新后面未确定的多种状态。
上代码:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
int n;
int a[1010];
int f[1010][1010];//f[i][j]指从第j个格子跳到第i个格子的最小花费
int main()
{cin >> n;for (int i = 1;i <= n;i++) cin >> a[i];memset(f, 0x3f, sizeof f);f[2][1] = a[2];for (int i = 1;i <= n;i++){//由i更新j 左 -> 右for (int j = 1;j <= n;j++){if (j - i >= 1) f[j][i] = min(f[j][i], f[j - i][i - 1] + a[j]);}//由i更新j 右 -> 左for (int j = n;j >= 1;j--){if(i + j <= n) f[j][i] = min(f[j][i], f[j + i][i] + a[j]);}}int ans = 0x3f3f3f3f;for (int i = 1;i <= n;i++){//cout << f[n][i] << " ";ans = min(ans, f[n][i]);}cout << ans << endl;return 0;
}
Part2光签题ⅡPart\ 2\ 光签题ⅡPart 2 光签题Ⅱ
LDUOJ 测试平台传送门
题目描述:
背景:光光被说题目出的太简单了,特此来谢罪了
题目来源:光光的签到题 === 光签题
光光说:”我不喜欢博弈论,但是我要把博弈论变成【dp】【dp】【dp】“
给出 NNN 堆石子,你有 MMM 次机会,每次只能拿 111 堆石子中的 xxx 个,当然需要花费:x2x^2x2。
求出拿完所有石子的最小花费
如果你求出最小花费,那么光光算你赢,否则应该算光光赢了吧(九折水平?)
输入:
两个整数 N,MN,MN,M
接下来 NNN 个整数 aia_iai 代表每堆石子的数量。
输出:
一个整数代表最小花费。
数据范围:
1≤N≤20001≤N≤20001≤N≤2000
N≤M≤4000N≤M≤4000N≤M≤4000
1≤ai≤1001≤a_i≤1001≤ai≤100
解题思路:
根据数据范围,我们可以先计算一下时间复杂度,NNN 堆石头,MMM 次机会,每堆石头最多能拿 aia_iai 次。2000×4000×100,大约是8e8的复杂度,在计算的过程中,还可以用一些优化条件,这样可以使复杂度降低一点,可以在1s1s1s之内跑完。
状态表示:f[i][j]f[i][j]f[i][j] 表示拿完前 iii 堆石头一共使用了 jjj 次机会所花费的最小代价。
属性:求最小值
状态转移:
f[i][j] = min(f[i][j], f[i - 1][j - k] + w);
这里再解释一下这个w,用k次机会拿完第i堆石头所花费的代价;
很明显,对于第i堆石头而言,在所用机会k确定的情况下,
让每次拿走的石头个数之间的差值最小可以使得所花费的代价最小。
上 ACACAC 代码:
Time:314MSTime: 314\ MSTime:314 MS
Memory:31.88MBMemory: 31.88\ MBMemory:31.88 MB
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int f[2010][4010];//f[i][j]表示拿完前i堆,并且一共花费j次机会
int a[2010];
int main()
{//freopen("6.in","r",stdin); int n, m;scanf("%d%d", &n, &m);for (int i = 1;i <= n;i++) scanf("%d", &a[i]);memset(f, 0x3f, sizeof f);for (int i = 0;i <= m;i++) f[0][i] = 0;for (int i = 1;i <= n;i++){for (int k = 1;k <= min(a[i], m);k++){int c = a[i] / k;int d = a[i] % k;int w = d * (c + 1) * (c + 1) + (k - d) * c * c;//下面这层循环的目的是拿当前所处状态//去更新后面所能更新到的未知状态//至于j的始端值与末端值的选择;//是根据每一堆石头都至少花费一次机会来确定的for (int j = k + i - 1;j <= m - n + i;j++) f[i][j] = min(f[i][j], f[i - 1][j - k] + w);}}printf("%d", f[n][m]);return 0;
}
小小的疑惑:
个人感觉下面这段代码的时间复杂度和上面AC代码的时间复杂度是一致的,带入超时数据进行循环次数测定,发现二则相差的次数也不算太多,下图展示出二者的循环次数:
有点疑惑的就是二则只是相差3e6而已嘛,竟然给T掉,这就很烦。
二者的思路大致是一样的只是在处理第二层循环与第三层循环的额时候给交换了一下考虑的次序。知道原因的大佬们请留步,给老弟一些指点吧,感谢,感谢!
【线性DP】跳格子问题 + 光签题(取石子游戏)相关推荐
- bzoj 1413: [ZJOI2009]取石子游戏(博弈+DP)
1413: [ZJOI2009]取石子游戏 Time Limit: 10 Sec Memory Limit: 162 MB Submit: 711 Solved: 470 [Submit][Sta ...
- BZOJ 1413: [ZJOI2009]取石子游戏 博弈+Dp
title BZOJ 1413 Description 在研究过Nim游戏及各种变种之后,Orez又发现了一种全新的取石子游戏,这个游戏是这样的: 有n堆石子,将这n堆石子摆成一排.游戏由两个人进行, ...
- 博弈问题-取石子(D题小牛vs小客)附取石子游戏总结
题目: 链接:https://www.nowcoder.net/acm/contest/75/D 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言6 ...
- 博弈论之取石子游戏的学习
以下内容来自转载: 博弈问题简介 所讨论的博弈问题满足以下条件: 玩家只有两个人,轮流做出决策 游戏的状态集有限,保证游戏在有限步后结束,这样必然会产生不能操作者,其输 对任何一种局面,胜负只决定于局 ...
- 博弈论——《取石子》《取石子游戏》
传送门:活动 - AcWing 思路: 结论:在所有堆的石子个数>1的情况下 只要石子数+石子堆数-1==b是奇数,那么先手必胜.b是不计算所有个数为1的石子堆得出的. b是奇数的情况下一定存在 ...
- BZOJ 1874: [BeiJing2009 WinterCamp]取石子游戏(SG函数)
Time Limit: 5 Sec Memory Limit: 162 MB Submit: 871 Solved: 365 [Submit][Status][Discuss] Descripti ...
- 威佐夫博弈:百练OJ:1067:取石子游戏
威佐夫博弈(Wythoff's game):有两堆各若干个物品,两个人轮流从任一堆取至少一个或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜. 百练OJ:1067:取石子游戏 ...
- POJ 1067 取石子游戏
取石子游戏 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 40917 Accepted: 13826 Descripti ...
- POJ-1067取石子游戏,威佐夫博弈范例题/NYOJ-161,主要在于这个黄金公式~~
取石子游戏 Time Limit: 1000MS Memory Limit: 10000K Description 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取 ...
最新文章
- p187让元素垂直居中
- RDKit | 通过Lipinski规则了解如何在RDKit中处理描述符
- 排序算法(还需补充)
- E: 您必须在 sources.list 中指定代码源(deb-src) URI 解决办法
- mvc crud_Spring MVC Hibernate MySQL集成CRUD示例教程
- python 中实现enum
- a站、b站、c站、d站、e站、f站、g站、h站、i站、j站、k站、l站、m站、n站…z站?
- 手把手教你搭建用户标签体系
- 移动硬盘写入数据报错“MS-DOS功能无效”,或移动硬盘内新建文件夹报错0x8000FFFF灾难性错误
- 算法设计 L型组件填图问题
- 将论文奇数页与偶数页页眉添加不同的下划线
- 499服务器响应,一边制造,一边讲解http状态码502|504|499|500
- TP-LINK路由器配置
- 4699. 如此编码
- STM32系统时钟详解
- 2018 51信用卡春招后端开发实习题解
- Theory: String basics(理论:字符串基础)
- 未来的全能保姆机器人作文_未来的保姆机器人
- 面试总结——Java高级工程师
- 彻底搞明白梯度下降算法1:方向导数与梯度概念理解
热门文章
- [前端基础] CSS3 篇
- 浅谈手机系统——iOS
- 苹果刷机服务器验证失败,iPhone手机刷机报错最全总结 教你学会分析手机问题出在哪...
- Bzoj3687简单题(bitset)
- Axure 9.0.0.3687
- centos7 telnet访问mysql出错Connection closed by foreign host
- java斗地主发牌_java实现斗地主发牌系统
- iPhone 14 全系售价及配置曝光,绝了!
- PostgreSQL在Linux和Windows安装和入门基础教程
- 如何在电脑上运行知乎?