动态规划DP

  • 硬币
  • 蛋糕塔
  • 游荡的奶牛
  • 格斗

硬币

题目描述
农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为“Xoinc”的两人硬币游戏。
初始时,一个有N(5 <= N <= 2,000)枚硬币的堆栈放在地上,从堆顶数起的第I枚硬币的币值为C_i (1 <= C_i <= 100,000)。
开始玩游戏时,第一个玩家可以从堆顶拿走一枚或两枚硬币。如果第一个玩家只拿走堆顶的一枚硬币,那么第二个玩家可以拿走随后的一枚或两枚硬币。如果第一个玩家拿走两枚硬币,则第二个玩家可以拿走1,2,3,或4枚硬币。在每一轮中,当前的玩家至少拿走一枚硬币,至多拿走对手上一次所拿硬币数量的两倍。当没有硬币可拿时,游戏结束。 两个玩家都希望拿到最多钱数的硬币。请问,当游戏结束时,第一个玩家最多能拿多少钱呢?
输入格式
第1行:1个整数N 第2…N+1行:第i+1行包含1个整数C_i
输出格式
1个整数表示第1个玩家能拿走的最大钱数。
input
5
1
3
1
7
2
output
9

好难啊…看了我0.5h的题解才看懂的…
这道题目我们可以选择倒着推:因为最后一个因此必然是要取完的,因此可以确定状态一定是可行的。
我们给每一个金币自底向上标号为1-i(这里自然需要逆序读入)
状态:设f[i][j]表示某一方取完以后还剩下编号为1-i的金币,上一个人取了j枚金币的最大取值(显然上一个人取的金币编号一定大于i)。
转移:对于每一个状态我们必然需要知道一个当前所取的金币数k,必然和f[i-k][]有关,表示1-i堆中取了k,还剩下1~i-k枚金币;同样,也和f[][k]有关,前一个人转移到这个人的时候,当前取的是k,那么必然就是k;那么这个人当前取的金币数就是总金币减去下一个决策的金币(这里用sum[]记录金币的前缀和),可得状态转移方程:f[i][j]=max(sum[i]−f[i−k]),i≥kf[i][j]=max(sum[i]-f[i-k]),i≥kf[i][j]=max(sum[i]−f[i−k]),i≥k
优化:观察每一个f[i][j],对于每一个f[i][j-1],多余的决策只有选2j-1枚金币和2j枚,只要k等于这两个值做两遍转移,和原来求最大值取一个max即可。

#include<bits/stdc++.h>
using namespace std;
#define maxn 3000int a[maxn];
int sum[maxn];
int f[maxn][maxn];
//表示其中的一个人,拿金币的时候剩下了1-i,上一个人拿了j个金币的最大值 inline void read(int &readnum)
{int s=0,w=1;char c=getchar();while (c<'0' || c>'9') {if (c=='-') w=-1;c=getchar();}while (c>='0' && c<='9') s=s*10+c-48,c=getchar();readnum=s*w;
}int main(void)
{freopen("xoinc..in","r",stdin);freopen("xoinc..out","w",stdout);int n;read(n);for (int i=n;i;--i) read(a[i]);for (int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];for (int i=1;i<=n;++i)for (int j=1;j<=n;++j){f[i][j]=f[i][j-1];int k=2*j-1;if (i>=k) f[i][j]=max(f[i][j],sum[i]-f[i-k][k]);k=2*j;if (i>=k) f[i][j]=max(f[i][j],sum[i]-f[i-k][k]); }cout<<f[n][1];return 0;
}

蛋糕塔

题目描述
Hl高中要举行一场蛋糕塔比赛。注意,不是蛋糕比赛,而是蛋糕塔比赛。
学校会提供N种不同类型的蛋糕,第i种蛋糕的高度为Hi(5 <= H_i <= T),营养价值为Vi(1 <= Vi<= 1,000,000),并且保证所有蛋糕的高度为5的整数倍,每种类型的蛋糕没有数量限制。
蛋糕塔比赛的规则就是要求按照提供的蛋糕,垒成一个高度不超过T(1 <= T <= 1,000)的蛋糕塔,并且要求这个蛋糕塔所有蛋糕的营养价值累加和最高。
因为蛋糕不是很结实,参加比赛的小x发现一个现象,如果某块蛋糕的高度超过K,那么这块蛋糕下面的所有蛋糕的高度都将被压缩为自己高度的4/5,但是营养价值不会丢失。发现这个情况后的小x很兴奋,现在他想知道,如何安排自己的蛋糕塔,能让营养价值最高。
输入格式
第一行三个整数:N,T和K;
接下来N行,每行两个整数:Vi 和 Hi。
输出格式
一行,一个整数,表示答案。
样例数据
input
3 53 25
100 25
20 5
40 10
output
240

这道题完全属于一个完全背包的变形。对于不会完全背包可以戳这里,这里不再多讲。
对于这道题,一共有两种情况:
1.不用大蛋糕–>用小蛋糕做一次完全背包即可。
2.用大蛋糕–>把所有蛋糕压成五分之四做一遍完全背包得到数组f[i](其含义代表体积为i的背包所能容下的最大价值),对于每一个大蛋糕,答案就是f[t-h[i]].
代码如下:

#include<bits/stdc++.h>
using namespace std;
#define maxn 10000
#define maxT 120000 int n,t,k;
int h[maxn];
int v[maxn];
int f[maxT];inline void read(int &readnum)
{int s=0,w=1;char c=getchar();while (c<'0' || c>'9') {if (c=='-') w=-1;c=getchar();}while (c>='0' && c<='9') s=s*10+c-48,c=getchar();readnum=s*w;
}int main(void)
{freopen("cheese..in","r",stdin);freopen("cheese..out","w",stdout);read(n);read(t);read(k);for (int i=1;i<=n;++i) read(v[i]),read(h[i]);for (int i=1;i<=n;++i)for (int j=h[i];j<=t*5/4;++j)f[j]=max(f[j],f[j-h[i]]+v[i]);int ans=f[t];for (int i=1;i<=n;++i)if (h[i]>=k) ans=max(ans,f[(t-h[i])*5/4]+v[i]);cout<<ans<<endl;return 0;
}

游荡的奶牛

题目描述
奶牛们在被划分成N行M列(2 <= N <= 100; 2 <= M <= 100)的草地上游走,试图找到整块草地中最美味的牧草。Farmer John在某个时刻看见贝茜在位置(R1, C1),恰好T (0 < T <= 15)秒后,FJ又在位置(R2, C2)与贝茜撞了正着。FJ并不知道在这T秒内贝茜是否曾经到过(R2, C2),他能确定的只是,现在贝茜在那里。
设S为奶牛在T秒内从(R1, C1)走到(R2, C2)所能选择的路径总数,FJ希望有一个程序来帮他计算这个值。每一秒内,奶牛会水平或垂直地移动1单位距离(奶牛总是在移动,不会在某秒内停在它上一秒所在的点)。草地上的某些地方有树,自然,奶牛不能走到树所在的位置,也不会走出草地。
现在你拿到了一张整块草地的地形图,其中’.‘表示平坦的草地,’*‘表示挡路的树。你的任务是计算出,一头在T秒内从(R1, C1)移动到(R2, C2)的奶牛可能经过的路径有哪些。
输入格式
第1行: 3个用空格隔开的整数:N,M,T
第2…N+1行: 第i+1行为M个连续的字符,描述了草地第i行各点的情况,保证字符是’.‘和’*'中的一个
第N+2行: 4个用空格隔开的整数:R1,C1,R2,以及C2
输出格式
第1行: 输出S,含义如题中所述
input
4 5 6
.
.


1 3 1 5
output
1

这道题,我们可以用时间来划分阶段。
f[i][j][k]表示位置i,j在时间为k的时候的方案数
f[i][j][k]=max(f[i−1][j][k−1],f[i+1][j][k−1],f[i][j−1][j−1],f[i][j+1][k−1])f[i][j][k]=max(f[i-1][j][k-1],f[i+1][j][k-1],f[i][j-1][j-1],f[i][j+1][k-1])f[i][j][k]=max(f[i−1][j][k−1],f[i+1][j][k−1],f[i][j−1][j−1],f[i][j+1][k−1])
注意一个前提,转移的点不能是障碍。
代码如下:

#include<bits/stdc++.h>
using namespace std;
#define maxn 200
#define maxt 30int n,m,t,r1,c1,r2,c2;
char a[maxn][maxn]={};
int f[maxn][maxn][maxt]={};  int main()
{freopen("ctravel.in","r",stdin);freopen("ctravel.out","w",stdout);cin>>n>>m>>t;for (int i=1;i<=n;++i)for (int j=1;j<=m;++j)cin>>a[i][j];cin>>r1>>c1>>r2>>c2;f[r1][c1][0]=1;for (int k=1;k<=t;++k)for (int i=1;i<=n;++i)for (int j=1;j<=m;++j){if (a[i][j]=='*') continue;if (a[i+1][j]=='.') f[i][j][k]+=f[i+1][j][k-1];if (a[i-1][j]=='.') f[i][j][k]+=f[i-1][j][k-1];if (a[i][j-1]=='.') f[i][j][k]+=f[i][j-1][k-1];if (a[i][j+1]=='.') f[i][j][k]+=f[i][j+1][k-1];}cout<<f[r2][c2][t]<<endl;fclose(stdin);fclose(stdout);return 0;
}

格斗

题目描述
格斗俱乐部是格斗爱好者的一个组织,在这里,格斗者们能通过与别的成员进行格斗来释放自己的压力与轻松自己的情绪。
最近俱乐部举行了一场比赛,该比赛有N位选手参加,他们将围成一个圆圈,每一场比赛圈内任意的两位相邻的选手均可进行相互的格斗,胜利者将留在圈内进入下轮比赛而失败者则直接被送往医院(没有平局)。比赛是残酷的,最后圈内将只剩下一位选手,他将是总冠军。
我们做个奇怪的假设,两位选手进行格斗,他们比赛的结果总是确定的。虽然俱乐部的成员们都很喜欢格斗,但是他们仍然很希望能获得总冠军。
现在你通过统计已经知道了任意两位选手格斗的结果,你有责任告诉每位选手,如果赛程合适安排的话,他是否可能成为总冠军。
输入格式
数据第一行是一个整数N,(1<=N<=40),表示比赛的选手数量。
接下来给出一个N*N的“0”、“1”矩阵A(行内用空格隔开),第i行第j列为 1表示选手i能战胜选手j,否则选手j能战胜选手i。
你可以假定Aij与Aji(i≠j)均是不同的且Aii=0。比赛开始时所有选手按顺时针方向由编号1到编号N站成一个圈,初始时编号1与编号N的选手是相邻的。
输出格式
输出包含N行,每行为一个整数“0”或“1”,“1”表示第i号选手有可能成为冠军,“0”表示不可能。
样例数据
input

3
0 1 1
0 0 1
0 0 0
output
1
0
0

区间DP。
我们可以设f[i][j][k]表示第i个人到第j个人之间,编号为k的人是否能够胜利。(1=胜利/0=失败)
在最简单的区间DP中,起点i,中间点k,结束点j中间暴力查找i-k中是否能打败k+1-j的人。
直接判断即可。
对于环形的处理,重新将环复制一边即可。

#include<bits/stdc++.h>
using namespace std;int a[200][200];
int f[100][100][100];int main()
{freopen("data.in","r",stdin);freopen("data.out","w",stdout);int n;cin>>n;for (int i=1;i<=n;++i)for (int j=1;j<=n;++j){cin>>a[i][j];a[i+n][j]=a[i][j+n]=a[i+n][j+n]=a[i][j];} //环形处理int m=n<<1;for (int i=1;i<=m;++i) f[i][i][i]=1;for (int len=2;len<=m;++len)for (int i=1;i+len-1<=m;++i){int j=i+len-1;for (int k=i;k<j;++k)for (int p1=i;p1<=k;++p1)if (f[i][k][p1])for (int p2=k+1;p2<=j;++p2)if (f[k+1][j][p2]) if (a[p1][p2]==1) f[i][j][p1]=1;else f[i][j][p2]=1;} for (int i=1;i<=n;++i) {int flag=0;for (int j=1;j<=n;++j) if (f[j][j+n-1][i]==1){flag=1;break;}cout<<flag<<endl;}fclose(stdin);fclose(stdout);return 0;
}

【习题详解】动态规划DP:硬币游戏 蛋糕 游荡的奶牛 决斗相关推荐

  1. java动态规划凑硬币问题,详解动态规划最少硬币找零问题--JavaScript实现

    硬币找零问题是动态规划的一个经典问题,其中最少硬币找零是一个变种,本篇将参照上一篇01背包问题的解题思路,来详细讲解一下最少硬币找零问题.如果你需要查看上一篇,可以点击下面链接: 详解动态规划01背包 ...

  2. 详解动态规划最长公共子序列--JavaScript实现

    前面两篇我们讲解了01背包问题和最少硬币找零问题.这篇将介绍另一个经典的动态规划问题--最长公共子序列.如果没看过前两篇,可点击下面链接. 详解动态规划最少硬币找零问题--JavaScript实现 详 ...

  3. 详解动态规划01背包问题--JavaScript实现

    对其他动态规划问题感兴趣的,也可以查看 详解动态规划最少硬币找零问题--JavaScript实现 详解动态规划最长公共子序列--JavaScript实现 一开始在接触动态规划的时候,可能会云里雾里,似 ...

  4. 状态压缩动态规划部分习题详解

    状态压缩动态规划部分习题详解 状压DP部分题目详解 状态压缩动态规划部分习题详解 简介 经典子集类问题 原子弹 最短路与状压DP结合 送礼物 P3959宝藏 旅游 经典网格类 铺地砖 一笔画 其他类型 ...

  5. 数据结构(C语言版) 第 六 章 图 知识梳理 + 习题详解

    目录 一. 图的基本定义和术语 一.图的基本概念 1.度 2.连通 (1)连通图 (2)强连通/强连通图 3.回路 4.完全图 二.图的三种存储结构 1.邻接矩阵表示法 2.邻接表(链式)表示法 3. ...

  6. c语言将AOE网络的数据写入TXT文档中,数据结构与算法学习辅导及习题详解.张乃孝版-C/C++文档类资源...

    数据结构与算法学习辅导及习题详解.张乃孝版.04年10月 经过几年的努力,我深深体会到,编写这种辅导书要比编写一本湝通教材困难得多. 但愿我的上述理想,在本书中能够得以体现. 本书的组织 本书继承了& ...

  7. 数据结构(C语言版) 第 八 章 排序 知识梳理 + 习题详解

    目录 一.归并排序 二.交换排序 1.快速排序 2.冒泡排序 三.插入排序 1.直接插入排序(基于顺序查找) 2.折半插入排序(基于折半查找) 3.希尔排序(基于逐趟缩小增量) 四.选择排序 0.直接 ...

  8. Python面对对象编程——结合面试谈谈封装、继承、多态,相关习题详解

    1.面向对象的三大特征 封装:属性和方法放到类内部,通过对象访问属性或者方法,隐藏功能的实现细节.当然还可以设置访问权限; 继承:子类需要复用父类里面的属性或者方法,当然子类还可以提供自己的属性和方法 ...

  9. 数学物理方法pdf_《数学物理方法》周明儒(第2版)补充材料与习题详解

    说明: 1.本资源为江苏师范大学 周明儒 教授所编著<数学物理方法>(第二版)配套电子资源: 2.由于Abook限制下载原版PDF,故本人高清截图保存整理为PDF格式供使用该书的同学使用, ...

最新文章

  1. Visual C++——《可视化编程技术》实验报告——绘图与文本操作
  2. java 请求http get_java http get/post请求
  3. 鸿蒙系统小卡片,升级鸿蒙101版本,UI审美升级了
  4. CSS中盒模型的理解
  5. mysql写入监控_zabbix 自定义key 监控mysql增删查改
  6. 关于自定义控件,可以编译通过,但是用时提示无法创建新实例。
  7. django 学习 (四) 模板标签
  8. LeetCode 720. 词典中最长的单词(Trie树)
  9. 为什么说读博是最好的选择?
  10. android画布原理,Android触摸事件如何实现笔触画布详解
  11. 【BZOJ4568】幸运数字,树链剖分/倍增+维护线性基
  12. ES5和ES6类的知识
  13. vmware esxi 升级 SCSI RAID卡驱动
  14. 阅读《软件工程—理论方法与实践》第五章心得体会
  15. 如何从iPhoto检索丢失的照片?
  16. 09. Django基础:URL反向解析
  17. atitit.修复xp 操作系统--重装系统--保留原来文件不丢失
  18. 2000-2019全国各省分品种能源消费量
  19. C++ Primer 5th 源代码使用说明
  20. 目的地址和ARP地址应答中的源地址

热门文章

  1. 纯卡西欧计算器5800P坐标正反算
  2. 你对前端开发岗的看法
  3. 手机账本软件哪些可以实现随手记录
  4. 51信用卡2018校园招聘编程题学习
  5. 腾讯AI Lab发布智能创作助手「文涌 (Effidit)」,用技术助力「文思泉涌」
  6. matlab 符号表达式正负,如何在Matlab上为符号表达式编写`lhs()`或`rhs()`函数
  7. docker下mysql主从搭建
  8. 【毕业设计】stm32单片机智能扫地机器人 - 嵌入式 物联网
  9. 阿里云服务器永久性修改主机名方法
  10. 自我管理数据缓冲区内存