北大暑期学习之动态规划
来源:互联网 发布:服务器与数据库的区别 编辑:程序博客网 时间:2024/05/20 16:00
例题一:数字三角形
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
此题是从顶部走到底部,所经过的路径上的数字之和最大,路径上的每一步只能左下或者右下走,求出最大和即可。
一.二维数组做
#include<iostream>
#include<algorithm>
#define max 101
Int D[max][max];
Int n;
Int maxsum(int i,int j)
{
If(i==n)
Return D[i][j];
Int x=maxsum(i+1,j);
Int y=maxsum(i+1,j+1);
Return max(x,y)+D[i][j];
}
Int main()
{
Int i,j;
Cin>>n;
For(i=1;i<=n;i++)
For(j=1;j<=n;j++)
Cin>>D[i][j];
Cout<<maxsum(1,1)<<endl;
}
此方法会超时
改进
如果每算出一个maxsum(r,j)就保存起来,下次用到其值时直接取用,则可免去重复计算。
#include<iostream>
#include<algorithm>
#define max 101
Int D[max][max];
Int n;
Int maxsum(int i,int j)
{
If(maxsum(i,j)!=-1)
Return maxsum[i][j];
If(i==n)
Maxsum[i][j]=D[i][j];
Else
{
Int x=maxsum(i+1,j);
Int y=maxsum(i+1,j+1);
Maxsum[i][j]=max(x,y)+D[i][j];
}
Return maxsum[i][j];
}
Int main()
{
Int i,j;
Cin>>n;
For(i=1;i<=n;i++)
For(j=1;j<=n;j++)
{
Cin>>D[i][j];
Maxsum[i][j]=-1;
}
Cout<<maxsum(1,1)<<endl;
}
递归成递推
#include<iostream>
#include<algorithm>
#define max 101
Int D[max][max];
Int n;
Int maxsum[max][max];
Int main()
{
Int i,j;
Cin>>n;
For(i=1;i<=n;i++)
For(j=1;j<=i;j++)
Cin>>D[i][j];
For(i=1;i<=n;i++)
Maxsum[n][j]=D[n][j];
For(i=n-1;i>=1;i--)
For(int j=1;j<=i;j++)
Maxsum[i][j]=max(maxsum[i+1][j],maxsum[i+1][j+1])+D[i][j];
Cout<<maxsum(1,1)<<endl;
}
空间优化
用一维数组
#include<iostream>
#include<algorithm>
#define max 101
Int D[max][max];
Int n;
Int *maxsum;
Int main()
{
Int i,j;
Cin>>n;
For(i=1;i<=n;i++)
For(j=1;j<=i;j++)
Cin>>D[i][j];
Maxsum=D[n];
For(int i=n-1;i>=1;--i)
For(int j=1;j<=i;j++)
Maxsum[j]=max(maxsum[j],maxsum[j+1])+D[i][j];
Cout<<maxsum[1]<<endl;
}
递归到动规的一般转化方法
递归有n个参数,就定义了一个n维数组,数组的下标是递归函数的参数的取值范围,数组元素的值是递归函数的返回值,这样就可以从边界值开始,逐步填充数组,相当于计算递归函数值的逆过程。
能用动规解题的问题的特点:
1.问题具有最优子结构性质。
2.无后效性
例题二:最长上升子序列
找出状态转移方程
人人为我递推型动态规划
#include<iostream>
#include<algorithm>
#define max 1010
Int a[max];
Int maxlen[maxn];
Int main()
{
Int n;
Cin>>n;
For(int i=1;i<=n;++i)
{
Cin>>a[i];
Maxlen[i]=1;
}
For(int i=2;i<=n;i++)
For(int j=1;j<i;j++)
{
If(a[i]>a[j])
Maxlen[i]=max(maxlen[i],maxlen[j]+1);
}
}
int ans=0;
for(i=1;i<=n;i++)
{
ans=max(ans,maxlen[i]);
}
printf("%d\n",ans);
return 0;
}
我为人人递推型动规程序
#include<iostream>
#include<algorithm>
#define max 1010
Int a[max];
Int maxlen[maxn];
Int main()
{
Int n;
Cin>>n;
For(int i=1;i<=n;++i)
{
Cin>>a[i];
Maxlen[i]=1;
}
For(int i=1;i<=n;i++)
For(int j=i+1;j<=n;j++)
{
If(a[j]>a[i])
Maxlen[j]=max(maxlen[j],maxlen[i]+1);
}
}
int ans=0;
for(i=1;i<=n;i++)
{
ans=max(ans,maxlen[j]);
}
printf("%d\n",ans);
return 0;
}
例题三:最长公共子序列
#include<iostream>
#include<cstring>
Using namespace std;
Char sz1[100];
Char sz2[1000];
Int maxlen[1000][1000];
Int main()
{
While(cin>>sz1>>sz2)
{
Int length1=strlen(sz1);
Int length2=strlen(sz2);
Int ntemp;
Int i,j;
For(i=0;i<=length1;i++)
Maxlen[i][0]=0;
For(j=0;j<=length2;j++)
Maxlen[0][j]=0;
For(i=1;i<=length1;i++)
{
For(j=1;j<=length2;j++)
{
If(sz1[i-1]==sz2[j-1])
Maxlen[i][j]=maxlen[i-1][j-1]+1;
Else
Maxlen[i][j]=max(maxlen[i][j-1],maxlen[i-1][j]);
}
}
Cout<<maxlen[length1][length2]<<endl;
}
RETURN 0;
}
例题四:最佳加法表达式
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int dp[100][200];
char str[500];
int change(int x,int y)
{
int t=0;
for(int i=x;i<=y;i++)
{
t*=10;
t+=(str[i]-'0');
}
return t;
}
int main()
{
int n,m,i,j,k;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
dp[i][j]=999999999;
}
}
for(i=1;i<=n;i++)
{
dp[0][i]=change(1,i);
}
for(i=1;i<=m;i++)
for(j=i;j<=n;j++)
for(k=i;k<=j;k++)
{
dp[i][j]=min(dp[i][j],dp[i-1][k]+change(k+1,j));
}
printf("%d\n",dp[m][n]);
}
return 0;
}
例题五:神奇的口袋
递归解法
#include<iostream>
Using namespace std;
Int a[30];
Int n;
Int ways(int w,int k)
{
If(w==0)
Return 1;
If(k<=0)
Rerturn 0;
Return ways(w,k-1)+ways(w-a[k],k-1);
}
Int main()
{
Cin>>n;
For(int i=1;i<=n;i++)
Cin>>a[i];
Cout<<ways(40,n);
Return0;
}
动规解法
#include<iostream>
Using namespace std;
Int a[30] ;int n;
Int ways[40][30];
Int main()
{
cin>>n;
Memset(ways,0,sizeof(ways));
For(int i=1;i<=n;i++)
{
Cin>>a[i];
Ways[0][i]=1;
}
ways[0][0]=1;
For(int w=1;w<=40;w++)
{
For(int k=1;k<=n;k++)
{
Ways[w][k]=ways[w][k-1];
If(w-a[k]>=0)
Ways[w][k]+=ways[w-a[k]][k-1];
}
}
Cout<<ways[40][n];
Return 0;
}
例题六:0-1背包问题
F[i][j]表示取前i种物品,使他们总体积不超过j的最优取法取得的价值总和
F[i][j]=max(F[i-1][j],F[i-1][j-w[i]]+d[i]);
f[n][m]=f[n-1][m-w[n]]+v[n]第n件物品放入背包
f[n][m]=f[n-1][m] 第n件物品不放入背包里
#include<iostream>
using namespace std;
Int n=3403;
Int m=12881;
Int f[m];
Int c[n],v[n];
Int main()
{
Int n,m;
While(cin>>n>>m)
{
Int i,j;
For(i=1;i<=n;i++)
{
Cin>>c[i]>>v[i];
}
Memset(f,0,sizeof(f));
For(i=1;i<=n;i++)
{
For(j=m;j>=c[i];j--)
{
If(f[j]<f[j-c[i]]+v[i])
f[j]=f[j-c[i]]+v[i];
}
}
Cout<<f[m]<<endl;
}
Return 0;
}
排列计数
如 1 2 3 4的全排列 共有4!种,求第10个的排列数是?
先试1,1后有三个数3!=6 6<10说明首位放1偏小
问题转化为求2开头的序列10-6=4 3!=6 6>4说明首位为2
此思想还未掌握
状态压缩动态规划
- 北大暑期学习之动态规划
- 北大暑期学习之搜索
- 北大暑期学习之并查集
- 北大暑期学习之数学问题
- 北大暑期学习之最短路
- 北大暑期学习之最小生成树
- 北大暑期学习之强联通分量
- 北大暑期学习之线段树与树状数组
- 北大暑期学校学习总结
- 学习ACM之动态规划
- 学习ACM之动态规划
- 学习ACM之动态规划
- 算法学习之- 动态规划
- ACM - 暑期第四天:动态规划
- 暑期规划
- 暑期规划
- 动态规划学习之石子归并
- 【算法学习笔记】之动态规划
- Xcode命令Archive导出4个ipa包的含义
- Header First HTML and CSS章后bullet points总结之Chapter 10
- 如何将磁盘从GPT格式转换成MBR格式——或MBR2GPT
- 怎样打印linux/mac环境变量
- uva 156 Ananagrams 解题报告
- 北大暑期学习之动态规划
- js 匀速/缓动动画 简单封装
- pl/sql developer调试定位到出错过程
- 原型模式——文档复制
- 北大暑期学习之数学问题
- 如何成为一名优秀的iOS开发工程师
- 北大暑期学习之搜索
- 北大暑期学习之线段树与树状数组
- 北大暑期学习之最短路