方格取数(简单版)+小烈送菜(不知道哪来的题)-----------奇怪的dp增加了!
一、方格取数:
设有N*N的方格图(N<=20),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0。
某人从图的左上角的A(1,1) 点出发,可以向下行走,也可以向右走,直到到达右下角的B(n,n)点。在走过的路上(包括起点在内),他可以取走方格中的数(取走后的方格中将变为数字0)。此人从A点到B 点共走两次,试找出2条这样的路径,使得取得的数之和为最大。
思路:emm...这咋写啊,好像是dp???可是你选了一个数后,第二次取数的时候不就不能取了,这不是有后效性了吗。。。
所以这道题的思路很清奇:两个人同时走。
这啥意思呢,简单来说,你的dp数组需要开四维,同时记录两个人的位置及状态,dp[i1][j1][i2][j2]。
既然我们一个人走两次会有后效性,那么我们可以认为是两个人同时在走,同时取数,这样就没有后效性了。
同时,转移的时候,就会有四种转移过程,第一个人可以从左或是从上过来,第二个人亦是。
转移方程:if(i1==i2&&j1==j2)dp[i1][j1][i2][j2]=max(dp[i1][j1][i2][j2],四种情况)+val[i1][j1];(这个意思是指两个人恰好走到一起去了,但是数只能取一次)
else dp[i1][j1][i2][j2]=max(dp[i1][j1][i2][j2],四种情况)+val[i1][j1]+val[i2][j2];
如下:
if(i1==i2&&j1==j2)dp[i1][j1][i2][j2]=max(dp[i1][j1-1][i2][j2-1],max(dp[i1-1][j1][i2][j2-1],max(dp[i1-1][j1][i2-1][j2],dp[i1][j1-1][i2-1][j2])))+val[i1][j1];
else dp[i1][j1][i2][j2]=max(dp[i1][j1-1][i2][j2-1],max(dp[i1-1][j1][i2][j2-1],max(dp[i1-1][j1][i2-1][j2],dp[i1][j1-1][i2-1][j2])))+val[i1][j1]+val[i2][j2];
啊啊啊啊太丑了太丑了
还有优化的方法:我们注意到,i1+j1==i2+j2==time(因为同时走的,速度也一样)
我们可以压缩成三维dp[i1][i2][time]遍历的时候跟上面大体一样,只要用time-i代替j就行了,注意time的循环范围!
代码全貌:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=21;
int dp[21][21][21][21],val[21][21];
int main(){
int n;scanf("%d",&n);
while(1){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(x==0&&y==0&&z==0)break;
val[x][y]=z;
}
for(int i1=1;i1<=n;i1++){
for(int j1=1;j1<=n;j1++){
for(int i2=1;i2<=n;i2++){
for(int j2=1;j2<=n;j2++){
if(i1==i2&&j1==j2){
dp[i1][j1][i2][j2]=max(dp[i1][j1-1][i2][j2-1],max(dp[i1-1][j1][i2][j2-1],max(dp[i1-1][j1][i2-1][j2],dp[i1][j1-1][i2-1][j2])))+val[i1][j1];
}else{
dp[i1][j1][i2][j2]=max(dp[i1][j1-1][i2][j2-1],max(dp[i1-1][j1][i2][j2-1],max(dp[i1-1][j1][i2-1][j2],dp[i1][j1-1][i2-1][j2])))+val[i1][j1]+val[i2][j2];
}
}
}
}
}
printf("%d",dp[n][n][n][n]);
return 0;
}
二、小烈送菜
题目大意:一共有n位客人从1到n顺序排列,每位顾客i有满意值W[i],服务员小烈可以从1到n再从n走到1,在期间他到达i时可以选择送菜或不送,但是要求最后回到1时所有菜都送完,当送完菜给i后再送菜给j时,可以得到满意值Wi×Wj,问如何上菜总满意值最大(第一位被送菜的顾客不提供满意值)
思路分析:
这道题与方格取数很类似,小烈需要从1到n再从n到1走两遍,所以我们可以考虑同时维护两个小烈同时走,然后到n结束。
性质1:W[i]*W[j]==W[j]*W[i]
这意味着你从1到n走一遍和从n到1走一遍是等效的,你完全可以认为你从1到n中送菜的顾客1--->i--->j--->n满意度是W[1]*W[i]+W[i]*W[j]+W[j]*W[n],如果你反过来也一样:n--->j--->i--->1满意度是W[n]*W[j]+W[j]*W[i]+W[i]*W[1];显然两者等效。
(通过这条性质,我们可以把思路中的两个小烈都改为从1到n去走)
接下来我们需要定义dp数组:
因为需要定义的无后效性,所以我们保证:当小烈1位于i位置送菜,小烈2位于j位置送菜时,所有位置小于i、j的顾客都已经被送过菜了。
dp[i][j]表示小烈1位于i,小烈2位于j时的满意度最大值。
转移方程:
i可以从前一个状态k转移过来,j也是,但是这样去枚举k1,k2很麻烦(基本算不出来),所以我们考虑由i,j向后推。
我们可以知道,因为dp[i][j]表示i,j之前的所有点都被遍历过,所以i,j的下一个状态一定是i,i+1或i+1,j或j+1,j或i,j+1。这个根据i,j的大小而定,dp[i][j]的下一个状态一定是i,j两个小烈中靠前的那个的前面一步(否则就不满足i,j前的所有顾客都被遍历过了)。我们可以得到这样的方程:
if(i>j){
dp[i+1][j]=max(dp[i+1][j],dp[i][j]+a[i]*a[i+1]);
dp[i][i+1]=max(dp[i][i+1],dp[i][j]+a[j]*a[i+1]);
}else{
dp[i][j+1]=max(dp[i][j+1],dp[i][j]+a[j]*a[j+1]);
dp[j+1][j]=max(dp[j+1][j],dp[i][j]+a[i]*a[j+1]);
}
这样写固然是没有问题啦,但是4行代码还是有点复杂,我们可以这样想:
如果保证dp[i][j]中i,j的大小关系,那么就可以把转移方程缩至两个。
我们不妨保证i>j。(在遍历的时候j从0到i-1即可)
那么方程变成:
dp[i+1][j]=max(dp[i+1][j],dp[i][j]+a[i]*a[i+1]);
dp[i][i+1]=max(dp[i][i+1],dp[i][j]+a[j]*a[i+1]);
这样已经很优秀了,可是我们看到第两个方程中i+1>i,这并不满足我们的前提条件i>j
这时候我们要用到性质2:
dp[i][j]=dp[j][i]这很显然吧,两个小烈本质上是一样的,谁在i,谁在j不重要,结果也一定相同。
所以我们可以改造一下dp[i][i+1],把它变成dp[i+1][i],这样就满足我们的i>j了。
最后的完成方程:
dp[i+1][j]=max(dp[i+1][j],dp[i][j]+a[i]*a[i+1]);
dp[i+1][i]=max(dp[i+1][i],dp[i][j]+a[j]*a[i+1]);
代码全貌:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5510;
int dp[maxn][maxn],a[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){//注意这里j从0开始遍历,因为存在一种可能:一个小烈送完了1到i的所有客人菜
dp[i+1][j]=max(dp[i+1][j],dp[i][j]+a[i]*a[i+1]);
dp[i+1][i]=max(dp[i+1][i],dp[i][j]+a[j]*a[i+1]);
}
}
int Max=0;
for(int i=0;i<n;i++){
Max=max(Max,dp[n][i]+a[i]*a[n]);
}
//我们假设第一个小烈已经到了终点,那么第二个小烈只需要从当前位置到n即可,因为i到n的所有点已经被第一个小烈走过了
//而实际上n这个点是要“被送两次的”,因为小烈到n再回去的时候a[n]会用两次。
printf("%d",Max);
return 0;
}
方格取数(简单版)+小烈送菜(不知道哪来的题)-----------奇怪的dp增加了!的更多相关文章
- 小烈送菜——奇怪的dp
小烈送菜 题目描述 小烈一下碰碰车就被乐满地的工作人员抓住了.作为扰乱秩序的惩罚,小烈必须去乐满地里的"漓江村"饭店端盘子. 服务员的工作很繁忙.他们要上菜,同时要使顾客们尽量高兴 ...
- 线性DP之小烈送菜
小烈送菜 小烈一下碰碰车就被乐满地的工作人员抓住了.作为扰乱秩序的惩罚,小烈必须去乐满地里的"漓江村"饭店端盘子. 服务员的工作很繁忙.他们要上菜,同时要使顾客们尽量高兴.一位服务 ...
- [HNOI2009]双递增序列(洛谷P4728)+小烈送菜(内部训练题)——奇妙的dp
博主学习本题的经过嘤嘤嘤: 7.22 : 听学长讲(一知半解)--自己推(推不出来)--网上看题解--以为自己会了(网上题解是错的)--发现错误以后又自己推(没推出来)--给学长发邮件--得到正确解法 ...
- 洛谷 - P1004 - 方格取数 - 简单dp
https://www.luogu.org/problemnew/show/P1004 这道题分类到简单dp但是感觉一点都不简单……这种做两次的dp真的不是很懂怎么写.假如是贪心做两次,感觉又不能证明 ...
- HDU 1565 1569 方格取数(最大点权独立集)
HDU 1565 1569 方格取数(最大点权独立集) 题目链接 题意:中文题 思路:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流 那么原图周围不能连边,那么就能够分成黑白棋盘.源点 ...
- HDU 1565&1569 方格取数系列(状压DP或者最大流)
方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- hdu 1565 方格取数(1) 状态压缩dp
方格取数(1) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Su ...
- 棋盘DP三连——洛谷 P1004 方格取数 &&洛谷 P1006 传纸条 &&Codevs 2853 方格游戏
P1004 方格取数 题目描述 设有N $\times N$N×N的方格图(N $\le 9$)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字00.如下图所示(见样例): A ...
- 洛谷 P1004 方格取数 题解
P1004 方格取数 题目描述 设有 \(N \times N\) 的方格图 \((N \le 9)\),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字\(0\).如下图所示(见样例): ...
随机推荐
- 11.QT-ffmpeg+QAudioOutput实现音频播放器
1.前言 由于QAudioOutput支持的输入数据必须是原始数据,所以播放mp3,WAV,AAC等格式文件,需要解封装后才能支持播放. 而在QT中,提供了QMediaPlayer ...
- Python爬取NBA虎扑球员数据
虎扑是一个认真而有趣的社区,每天有众多JRs在虎扑分享自己对篮球.足球.游戏电竞.运动装备.影视.汽车.数码.情感等一切人和事的见解,热闹.真实.有温度. 受害者地址 https://nba.hupu ...
- $\TeX$ Gyre 字体安装过程与问题解决
目录 安装过程 1. 下载字体包 2. 安装字体 3. 测试范例文件 本文地址 https://www.cnblogs.com/oberon-zjt0806/p/13672426.html 本文只是一 ...
- [LeetCode]Mysql小本本
常用方法 累加型题目,可以考虑使用笛卡尔积进行自表连接,连接后的表进行where条件进行筛选.group by分组操作. union:需要把两列作一列可以用union,union的两张表查询的字段不一 ...
- 分别用canvas和css3的transform做出钟表的效果
两种方式实际上在js上的原理都是一样的.都是获取时间对象,再获取时间对象的时分秒,时分秒乘以其旋转一刻度(一秒.一分.一小时)对应的角度.css3中要赋值于transform:rotate(角度),c ...
- react项目结合echarts,百度地图实现热力图
一.最近在一个react项目(antd pro)中需要展示一个热力地图.需求是: 1.热力地图可缩放: 2.鼠标点击可以展示该点地理坐标,及热力值. 3.初始化时候自适应展示所有的热力点. 4.展示热 ...
- Vue Render自定义tabled单元格内容
解决问题 只举一个例子(我正好需要用到的) 在写中后台时, 如果对 表格组件 再度封装了, 比如这样的 以element-ui 为例: <template> <el-table :d ...
- 在浏览器输入 URL 回车之后发生了什么(超详细版)
前言 这个问题已经是老生常谈了,更是经常被作为面试的压轴题出现,网上也有很多文章,但最近闲的无聊,然后就自己做了一篇笔记,感觉比之前理解更透彻了. 这篇笔记是我这两天看了数十篇文章总结出来的,所以相对 ...
- NX导入DWG失败
给客户开发的NX导入DWG图纸功能,部分电脑偶尔出现导入失败的情况,且几乎没有规律可言.客户无法理解,坚持认为是代码的问题,毕竟使用的是我们二次开发的功能.我本机没有问题,在某些出问题的电脑上也尝试多 ...
- 《Mybatis进阶》肝了30天专栏文章,整理成册,免费获取!!!
持续原创输出,点击上方蓝字关注我吧 目录 前言 简介 如何获取? 总结 前言 Mybatis专栏文章写到至今已经有一个月了,从基础到源码详细的介绍了每个知识点,没什么多余的废话,全是工作.面试中常用到 ...