动态规划的优化
来源:互联网 发布:眼镜清洗机牌子知乎 编辑:程序博客网 时间:2024/06/05 04:55
目录
- 动态规划的优化
- 状态压缩
- COGS217USACO Open05 Disease Management
- 数位动规
- 区间满足条件的整数个数
- HDU2098不要 62
- BZOJ1026SCOI2009windy数
- 斜率优化
- BZOJ1010HNOI2008 玩具装箱toy
- 矩阵快速幂优化
- BZOJ1009HNOI2008GT考试
动态规划的优化
状态压缩
[COGS217][USACO Open05] Disease Management
N 头奶牛中共有D 种疾病,选择性地给一些奶牛挤奶,使得挤出牛奶中的疾病总数不超过K 种,求最多能给多少奶牛挤奶。
1≤N≤100,1≤D≤15,1≤K≤D
#include<iostream>#include<cstdio>using namespace std;int N,D,K;int f[1<<15+5];int ill[1005];bool ok[1<<15+5];int main(){ freopen("disease.in","r",stdin); freopen("disease.out","w",stdout); int i,j,x,y;scanf("%d%d%d",&N,&D,&K); for(i=1;i<=N;i++) { scanf("%d",&x); for(j=1;j<=x;j++) { scanf("%d",&y); ill[i]+=1<<(y-1); } } int tot=(1<<D)-1; for(i=0;i<=tot;i++) { int icnt=0; for(j=i;j;j>>=1) if(j&1) icnt++; if(icnt<=K) ok[i]=true; } for(i=1;i<=N;i++) for(j=tot;j>=0;j--) f[j|ill[i]]=max(f[j|ill[i]],f[j]+1); int ans=0; for(i=0;i<=tot;i++) if(ok[i]) ans=max(ans,f[i]); printf("%d\n",ans); return 0;}
数位动规
区间满足条件的整数个数
数位动规能解决一类形如求一个区间内满足条件的整数个数一类经典问题。
一般的做法是:记录
数位动规十分易懂且好写(所以说不经常出现),唯一的难点就在于前导零的处理,看三道题感受一下吧。
[HDU2098]不要 62
给定一个数字范围
[l,r] ,问满足不含有4 且不含有连续的两个数62 的数字的数量。
r≤106
这道题处理前导零可以在初始化 DP 数组时允许有前导零,然后在计算答案时对每一位分别统计,对一位只统计其整的部分(其中就包括了位数少的情况,因为之前算进去了),零的部分放到后面计算。
这样的做法虽然简单,但适用范围十分狭窄。
#include<iostream>#include<cstdio>#include<cstring>int f[10][10];inline void initDp(){ int i,j,k; f[0][0]=1; for(i=1;i<=7;i++) for(j=0;j<=9;j++) for(k=0;k<=9;k++) if(j!=4&&!(j==6&&k==2)) f[i][j]+=f[i-1][k];}int num[10];int solve(int x){ memset(num,0,sizeof(num)); int res=0,len=0; while(x) num[++len]=x%10,n/=10; for(i=len;i>=1;i--) { for(j=0;j<num[i];j++) if(!(num[i+1]==6&&j=2)) ans+=f[i][j]; if(num[i]==4||(num[i+1]==6&&num[i]=2)) break; } return res;}int main(){ int i; int n,m; initDp(); while(scanf("%d%d",&n,&m)&&n&&m) printf("%d\n",solve(m+1)-solve(n)); return 0;}
[BZOJ1026][SCOI2009]windy数
给定一个区间
[l,r] ,求满足相邻两个数字只差最小为2 的数的个数。
r≤2×109
由于这道题我们不能像
斜率优化
[BZOJ1010][HNOI2008] 玩具装箱toy
由题意,易得如下状态转移方程:
令
则
证明决策单调性
假设在状态
i 处的k 决策优于j 决策,即
f[k]+(g[i]−g[k]−L)2≤f[j]+(g[i]−g[j]−L)2 则对于
i 后的所有状态t ,要证明决策单调性即
f[k]+(g[t]−g[k]−L)2f[k]+(g[i]+v−g[k]−L)2f[k]+(g[i]−g[k]−L)2+2v⋅(g[i]−g[k]−c)+v22v⋅(g[i]−g[k]−c)≤≤≤≤f[j]+(g[t]−g[j]−L)2f[j]+(g[i]+v−g[j]−L)2f[j]+(g[i]−g[j]−c)2+2v⋅(g[i]−g[j]−L)+v22v⋅(g[i]−g[j]−L)
即证明g[k]≥g[j] (显然)证明完毕
那么接下来就要求斜率方程
加入决策
满足
/************************************************************** Problem: 1010 User: zhangche0526 Language: C++ Result: Accepted Time:176 ms Memory:2464 kb****************************************************************/#include<iostream>#include<cstdio>typedef long long ll;const int MAXN=5e4+5;ll n,L;ll f[MAXN],g[MAXN],que[MAXN];inline double calSlop(int j,int k){return (f[k]-f[j]+(g[k]+L)*(g[k]+L)-(g[j]+L)*(g[j]+L))/(2.0*(g[k]-g[j]));}int main(){ int i,j; scanf("%lld%lld",&n,&L);L++; for(i=1;i<=n;i++) scanf("%lld",&g[i]); for(i=2;i<=n;i++) g[i]+=g[i-1]; for(i=1;i<=n;i++) g[i]+=i; int hd,tl; hd=1,tl=0;que[++tl]=0; for(i=1;i<=n;i++) { while(hd<tl&&calSlop(que[hd],que[hd+1])<=g[i]) hd++; j=que[hd]; f[i]=f[j]+(g[i]-g[j]-L)*(g[i]-g[j]-L); while(hd<tl&&calSlop(que[tl],i)<calSlop(que[tl-1],que[tl])) tl--; que[++tl]=i; } printf("%lld\n",f[n]); return 0;}
矩阵快速幂优化
有时候我们会遇到一些状态转移方程是递推形式的动态规划问题,而数据范围很大时,我们使用朴素的递推方法会超时,这时我么你考虑用矩阵快速幂的方法将
[BZOJ1009][HNOI2008]GT考试
给出一个长度为
M 的十进制数字串,求在一个长度为N 的十进制数字串中有多少种不出现长度为M 的那个串(对K 取模),两个串中均允许出现前导零。
N≤109,M≤20,K≤103
这道题要是不看数据范围还感觉是数位动规,但
按顺序处理准考证号每一位,设
那么答案
- f[i][j]表示的每种方案不仅与其后j位有关,还应保证不含不吉利数
- 为避免重复,
f[i][j] 表示的每种方案都不含长度大于j且与不吉利数的前缀相同的后缀(否则就会出现:从1 到m 标号,不吉利数为123124 时,f[i][2] 计数的方案包含f[i][5] 计数的方案的情况)
状态转移:
比如:还是假设不吉利数为123124,那么 f[i][3]=f[i-1][2]+f[i-1][5],因为 f[i-1][2]末尾的*****12不能是**12312,所以需要f[i-1][5]补充
但若不吉利数为123123,那么 f[i][3]=f[i-1][2],因为 f[i][3]末尾的*****123不能是**123123
其中,
/************************************************************** Problem: 1009 User: zhangche0526 Language: C++ Result: Accepted Time:60 ms Memory:1288 kb****************************************************************/#include<iostream>#include<cstdio>#include<cstring>const int MAXL=25;int N,M,P;struct Mt{int m[MAXL][MAXL];Mt(){memset(m,0,sizeof(m));}};Mt operator *(Mt a,Mt b){ int i,j,k; Mt res; for(i=0;i<M;i++) for(j=0;j<M;j++) for(k=0;k<M;k++) res.m[i][j]=(res.m[i][j]+a.m[i][k]*b.m[k][j])%P; return res;}Mt qpow(Mt a,int n){ int i; Mt res; for(i=0;i<M;i++) res.m[i][i]=1; for(i=1;i<=N;i<<=1,a=a*a) if(i&n) res=res*a; return res;}int next[MAXL];char s[MAXL];int main(){ int i,j; scanf("%d%d%d",&N,&M,&P); scanf("%s",s+1); for(i=2,j=0;i<=M;i++) { while(j&&s[j+1]!=s[i]) j=next[j]; if(s[j+1]==s[i]) j++; next[i]=j; } Mt dp; for(i=0;i<M;i++) for(j=0;j<=9;j++) { int t=i; while(t&&s[t+1]-'0'!=j) t=next[t]; if(s[t+1]-'0'==j) t++; if(t!=M) dp.m[t][i]=(dp.m[t][i]+1)%P; } Mt res=qpow(dp,N); int ans=0; for(i=0;i<M;i++) ans=(ans+res.m[i][0])%P; printf("%d\n",ans); return 0;}
- 动态规划的优化
- 动态规划的优化
- 动态规划的优化技巧
- 动态规划_动态规划算法的优化技巧
- 动态规划算法的优化技巧
- 一类动态规划的四边形优化
- 动态规划算法的优化技巧
- 关于动态规划的单调队列优化
- 动态规划算法的优化技巧
- 动态规划算法的优化技巧
- 动态规划算法的优化技巧
- 动态规划算法的优化技巧
- 矩阵快速幂优化的动态规划
- ZOJ2676动态规划优化
- 动态规划 斜率优化
- 动态规划优化整理
- 动态规划优化
- 动态规划优化整理
- 【PAT】【Advanced Level】1020. Tree Traversals (25)
- [mysql]如何重置或设置mysql的自增id值
- 单向循环链表C++
- POJ 3258(二分——最大化最小值)
- POJ 3258(二分——最大化最小值)
- 动态规划的优化
- struts2链接数据库的简单登陆验证
- input 框上传多个文件以及文件校验
- 基于MATLAB利用模拟退火算法解决费马点问题
- 数据结构之AOV网与拓扑排序
- 新手上路之oracle 增,删,改,查操作 笔记
- 计算机系统要素:第四章 机器语言
- CCF中学生计算机程序设计入门篇练习2.4.1(NOI1001 温度转换) pascal
- 学习笔记——自动登陆