2021—10—31 上课笔记
DP主要的核心就是对于每道题专属的状态转移方程
动态规划过程是:
每次决策依赖于当前状态,又随即引起状态的转移。一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划(DP)。
基本思想与策略
基本思想与分治法类似,也是将待求解的问题分解为若干个子问题(阶段),按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。
动态规划的算法设计
1:找出最优解的性质,并描述其结构特征
2:递归定义最优值
3:以自底向上的方式计算最优值
4:根据计算最优值时得到的信息构造出最优解
能采用动态规划求解的问题的一般要具有3个性质
(1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
(2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
(3) 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)动态规划将原来具有指数级时间复杂度的搜索算法改进成了具有多项式时间复杂度的算法。其中的关键在于解决冗余,这是动态规划算法的根本目的。动态规划实质上是一种以空间换时间的技术,它在实现的过程中,不得不存储产生过程中的各种状态,所以它的空间复杂度要大于其它的算法。
使用动态规划求解问题,最重要的就是确定动态规划三要素
(1)问题的阶段
(2)每个阶段的状态
(3)从前一个阶段转化到后一个阶段之间的递推关系。
动态规划的具体步骤:
(1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。
(2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。
(3)确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两个阶段的状态之间的关系来确定决策方法和状态转移方程。
(4)寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
”简单“DP
1.股票买卖(P2569 [SCOI2010]股票交易):OpenJudge - 8464:股票买卖
(1)如果没有买卖两次的限制:
#include<bits/stdc++.h>
using namespace std;int main(void){ios::sync_with_stdio(false);cin.tie(0);int T;cin >> T;while(T--){int N; cin >> N;int a[N+1];for(int i=1;i<=N;i++)cin >> a[i];int dp[N+1][2];dp[1][0]=0;dp[1][1]=-a[1];for(int i=2;i<=N;i++){dp[i][0]=max(dp[i-1][1]+a[i],dp[i-1][0]);dp[i][1]=max(dp[i-1][0]-a[i],dp[i-1][1]);}int max1=max(dp[N][1]+a[N],dp[N][0]);cout << max1;if(T) cout << endl;}return 0;
}//dp[n][1],dp[n][0]表示到第n天手中还有,手中没有股票的利润
//dp[n][1]=max((dp[n-1][0]+(n-1)买入),dp[n-1][1])
//dp[n][0]=max((dp[n-1][1]+(n-1)卖出),dp[n-1][0])
//
//
(2):(12条消息) 股票买卖问题_u011402017的博客-CSDN博客_股票买卖的问题
这个写的很好
有两次的限制:
#include<bits/stdc++.h>
using namespace std;int main(void){ios::sync_with_stdio(false);cin.tie(0);int T;cin >> T;while(T--){int N; cin >> N;int a[N+1];for(int i=1;i<=N;i++)cin >> a[i];int dp[N+1][2][2];dp[1][1][0]=dp[1][0][0]=0;dp[1][0][1]=dp[1][1][1]=-a[1];for(int i=2;i<=N;i++){for(int k=0;k<=1;k++){dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][k][1]+a[i]);if(k==1) dp[i][k][1]=max(dp[i-1][k][1],-a[i]);else dp[i][k][1]=max(dp[i-1][k][1],dp[i-1][k+1][0]-a[i]);}
// dp[i][1][0]=max(dp[i-1][1][0],dp[i-1][1][1]+a[i]);
// dp[i][0][0]=max(dp[i-1][0][0],dp[i-1][0][1]+a[i]);
// dp[i][1][1]=max(dp[i-1][1][1],-a[i]);
// dp[i][0][1]=max(dp[i-1][0][1],dp[i][1][0]-a[i]);}cout << dp[N][0][0];if(T) cout << endl;}return 0;
}//dp[n][1],dp[n][0]表示到第n天手中还有,手中没有股票的利润
//dp[n][1]=max((dp[n-1][0]+(n-1)买入),dp[n-1][1])
//dp[n][0]=max((dp[n-1][1]+(n-1)卖出),dp[n-1][0])
//
//
2.区间DP:(能量项链):(但是有WA。。)
#include<bits/stdc++.h>
using namespace std;
int dp[300][300];int main(void){int N;cin >> N;int a[2*N];for(int i=0;i<N;i++){cin >> a[i];a[N+i]=a[i];}int max1=0;for(int j=1;j<N;j++)for(int i=0;i<N;i++)for(int k=0;k<j;k++){dp[i][i+j]=max(dp[i][i+j],dp[i][i+k]+dp[i+k+1][i+j]+a[i]*a[i+k+1]*a[i+j+1]);max1=max(max1,dp[i][i+j]);}cout << max1;return 0;
}//dp[0][n-1]=dp[0][i]+dp[i+1][n-1]+max(a[i]*a[0]*a[0],a[i]*a[i]*a[0])
//dp[i][j]=dp[i][k]+dp[k+1][j]+max(a[k]*a[i]*a[i],a[k]*a[k]*a[i])
//dp[i%N][(i+j)%N]=max(dp[i%N][(i+j)%N],dp[i%N][(i+k-1)%N]+dp[(i+k)%N][(i+j)%N]+a[i%N]*a[(i+k)%N]*a[(i+j+1)%N]);
//
//
这样就ok:
#include<bits/stdc++.h>
using namespace std;
int dp[202][202];int main(void){int N;cin >> N;int a[2*N];for(int i=0;i<N;i++){cin >> a[i];a[N+i]=a[i];}int max1=0;for(int i=1;i<2*N-1;i++)for(int j=i-1;i-j<N && j>=0;j--){for(int k=j;k<i;k++)dp[j][i]=max(dp[j][i],dp[j][k]+dp[k+1][i]+a[j]*a[k+1]*a[i+1]);max1=max(max1,dp[j][i]);}cout << max1;return 0;
}
3.树形DP(没有上司的舞会)
树形DPblog: 树形$dp$学习笔记 - _Lancy - 博客园 (cnblogs.com)
完全自己写的:
#include<bits/stdc++.h>
using namespace std;
struct Tree{int val,fa,wei,bok;Tree(int val=0,int fa=0,int wei=0,int bok=0):val(val),fa(fa),wei(wei),bok(bok){}
};queue<int> q;int main(void){int N;cin >> N;Tree a[N+1];a[0].fa=-1;int book[N+1]={0}; //标记0为叶节点(待用) 1不为叶节点(待待用) -1为使用过for(int i=1;i<=N;i++){cin >> a[i].val;}for(int i=1;i<=N-1;i++){int temp1,temp2;cin >> temp1 >> temp2;a[temp1].fa=temp2;book[temp2]=1;}for(int i=1;i<=N;i++){if(book[i]==0)q.push(i);a[a[i].fa].bok=1;}int max1=0;while(!q.empty()){int i=q.front();if(book[i]==-1){q.pop();continue;}if(a[i].bok==1){a[a[i].fa].bok=(a[i].val>a[i].wei)?1:0;a[i].val=max(a[i].val,a[i].wei);}else{if(a[i].val>=0)a[i].val+=a[i].wei;elsea[i].val=a[i].wei;a[a[i].fa].bok=1;}
// if(max1<a[i].val){
// cout << endl;
// cout << "max1:" <<max1 << " i:" << i << " a[i].val:" << a[i].val << endl;
// }max1=max(max1,a[i].val);if(a[i].fa!=-1){q.push(a[i].fa);a[a[i].fa].wei+=a[i].val;book[a[i].fa]=0;}book[i]=-1;q.pop();}cout << max1;return 0;
}
别人:
f[x][0]表示以x为根的子树,且x不参加舞会的最大快乐值
f[x][1]表示以x为根的子树,且x参加了舞会的最大快乐值
则f[x][0]=sigma{max(f[y][0],f[y][1])} (y是x的儿子)
f[x][1]=sigma{f[y][0]}+h[x] (y是x的儿子)
vector<int> son[max]表示一个节点的儿子
(树的直径):某一结点的最长分成两部分:它向下与它到根节点加上根节点的最大长度
这个写的真的很好:(14条消息) 求树的直径算法_weixin_30895603的博客-CSDN博客
还有这个:(14条消息) 树的直径_Reaearcher-Du-CSDN博客_树的直径
自己:
#include<bits/stdc++.h>
using namespace std;
const int INF=10000000;
vector<int> G[100000];
vector<int> E[100000];
int dis[100000];
bool vis[100000];void Init(void);
void dfs(int n);
int maxval,maxi;int main(void){int N;cin >> N;Init();for(int i=1;i<=N-1;i++){int t1,t2,t3;cin >> t1 >> t2 >> t3;G[t1].push_back(t2);E[t1].push_back(t3);G[t2].push_back(t1);E[t2].push_back(t3);}memset(dis,INF,sizeof(dis));dis[1]=0;dfs(1);int start=maxi;Init();memset(dis,INF,sizeof(dis));dis[start]=0;maxval=0;dfs(start);cout << maxval << endl;return 0;
}void Init(void){memset(vis,0,sizeof(vis));
}void dfs(int n){vis[n]=1;int size=G[n].size();for(int i=0;i<size;i++){int v=G[n][i];if(vis[v]==0){dis[v]=dis[n]+E[n][i];if(maxval<dis[v])maxi=v;maxval=max(maxval,dis[v]);dfs(v);}}
}
(毛毛虫)
4.背包问题:
(14条消息) 01背包问题相关优化大全(二维到一维)_曼切斯特的流氓的博客-CSDN博客
完全背包:反向改正向:(14条消息) 完全背包问题(详细解答)_曼切斯特的流氓的博客-CSDN博客_完全背包问题
分组背包:物品个数有限(二进制优化)
(14条消息) 背包九讲——全篇详细理解与代码实现_良月澪二的博客-CSDN博客_背包九讲
若要求恰好装满(非装满全赋值为正无穷)
6.状压DP:二进制表状态
(不能。。。的玉米田)
(互不侵犯):DP[i][j][num]
(炮兵阵地)
(动物园)
tip:异或操作
7.习题:
Misunderstood … Missing:具有后效性则从后开始DP
计算直线的交点个数:n条设有m条平行线,dp[n]=dp[n-m]+n*m
dp[n][m]表示以n为边数m为点数是否成功
8.bitset
9.dp与网络流
2021—10—31 上课笔记相关推荐
- 2021/10/31 前端开发之JavaScript+jQuery入门 第十二章jQuery事件与动画
目录 1.jQuery中的事件 1.1 事件的组成 1.2 基础事件 2.载入事件 3.鼠标事件 4.键盘事件 5.浏览器事件 6.表单事件 7.绑定事件 8.移除事件 9.复合事件 10.控制元素显 ...
- 一周碎碎念,2021.10.31,重启跑步
叨叨最近遇到的一些事以及见闻.思考. 1. [重要提醒]做好数据备份 这里不仅是指数据库的数据,也包括日常工作.生活中产生的数据,例如工作电脑(重要文档资料等).手机数据(照片.通信录等). 平时可能 ...
- 2017.10.31笔记
10.31笔记 1.js数据类型: ①基本数据类型:第一个:number 数字类型 NAN 非数类型 第二个:string 字符串,两个引号之间的内容 第三个:boolean 布尔值( true fa ...
- 2021.10.25-10.31 AI行业周刊(第69期):AI进化之路
本周<Opencv基础及AI项目实战>以及<Pytorch模型推理及多任务通用范式>两门课程已经完结. 两门课程中,针对所有完成作业的同学,都颁发了毕业证书. 并且对于完成比较 ...
- cs224w(图机器学习)2021冬季课程学习笔记10 Applications of Graph Neural Networks
诸神缄默不语-个人CSDN博文目录 cs224w(图机器学习)2021冬季课程学习笔记集合 文章目录 1. Graph Augmentation for GNNs 1.1 图特征增强Feature A ...
- cs224w(图机器学习)2021冬季课程学习笔记16 Community Detection in Networks
诸神缄默不语-个人CSDN博文目录 cs224w(图机器学习)2021冬季课程学习笔记集合 文章目录 1. Community Detection in Networks 2. Network Com ...
- cs224w(图机器学习)2021冬季课程学习笔记8 Colab 2
诸神缄默不语-个人CSDN博文目录 cs224w(图机器学习)2021冬季课程学习笔记集合 VX号"PolarisRisingWar"可直接搜索添加作者好友讨论. 更新日志: 20 ...
- cs224w(图机器学习)2021冬季课程学习笔记12 Knowledge Graph Embeddings
诸神缄默不语-个人CSDN博文目录 cs224w(图机器学习)2021冬季课程学习笔记集合 文章目录 1. Heterogeneous Graphs and Relational GCN (RGCN) ...
- Redis教程(上课笔记)
Redis教程 1. 什么是NoSql NoSQL一词最早出现于1998年,是Carlo Strozzi开发的一个轻量.开源.不提供SQL功能的关系数据库.2009年,Last.fm的Johan Os ...
最新文章
- 原生js清空上一个元素内容_原生JS实现动态添加新元素、删除元素方法
- 中国平民百姓与富翁的五大差距
- kuka程序备份_那智机器人系统备份步骤
- 书籍折页是什么效果_Word的书籍折页是什么 如何设置Word的书籍折页
- 如何通过网线连接两台电脑快速传输数据?
- java 正则匹配_正则表达式真的很强大,可惜你不会写
- libsvm中数据归一化的重要性
- IDC:今年全球认知和人工智能系统支出将突破125亿美元
- linux拆分文件会影响源文件吗,linux split拆分文件
- 如何通过企业微信做精细化社群运营
- Tajima‘s D群体遗传
- 除去google工具栏启动的GoogleToolbarNotifier.exe进程
- springboot + vue 全栈开发实战 读书感想
- 在命令窗中查询当前电脑IP
- Android笔记:浅析Android电视APP开发
- 申办高新技术企业,如何申请高新认定
- 4.28time和OS系统
- Android 识别SIM卡类型
- java poi导出Excel表格(动态表头)
- python安装 pymssql 异常