@TOC动态规划题目
一、经典背包问题
*
背包问题
给出n个物品的体积A[i][0]和其价值A[i][1],将他们装入一个大小为k的背包,最多能装入的总价值有多大?
*/
#include<stdio.h>
//N个背包
#define N 4
int max(int a, int b)
{
return a>b?a:b;
}
int main()
{
//i表示背包的编号 a[i][0] 表示背包的大小 a[i][1]表示背包的价值 a[0][0]表示背包的大小和 容量均为0
//大小 价值
int a[N+1][2]={ {0, 0},
{2, 3},
{3, 4},
{4, 5},
{5, 6}};
int k;
printf("请输入总容量的大小:");
scanf("%d",&k);
int sub[N+1][k+1];
//sub[i][j] j表示剩余容量 i表示 有几个背包可供选择
//a[i][j]容量为j的容器能装的价值的最大值
//0个背包可供选择的情况下 无论容量多大 均没得装 即最大价值均为0
for(int i=0;i<=k;i++)
{
sub[0][i]=0;
}
//在容量为0的情况下 无论多少个背包可共选择 !均装不下 即最大价值为0
for(int i=0;i<=N;i++)
{
sub[i][0]=0;
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=k;j++)
{
if(j>=a[i][0])
{
int m=a[i][1]+sub[i-1][j-a[i][0]]; //选择当前背包 当前背包的价值 加上 (剩下的背包选择中(i-1) 容量为 总容量减去当前背包的大小)的最高价选择
int n=sub[i-1][j]; //不选择当前背包 那就是容量为 j 背包选择为 i-1的最高选择
sub[i][j]=max(m,n);
}
else
{
//当前容量装不下这个背包 那么有i个背包的选择情况下,他的最大值也只能是有i-1个背包的最大值
sub[i][j]=sub[i-1][j];
}
}
}
for(int i=0;i<=N;i++)
{
for(int j=0;j<=k;j++)
{
printf("%d ",sub[i][j]);
}
printf("\n");
}
}
二、不能连续的子序列最大和
//动态规划里面的
#include<stdio.h>
#define N 7
int max(int a,int b)
{
return a>b?a:b ;
}
//不能连续的子序列最大和
int main()
{
int array[N]={1,2,4,1,7,8,3};
int opt[N];
opt[0]=array[0];
opt[1]=max(array[0],array[1]);
int prev[N]={0};
for(int i=N-1;i>=2;i--)//如果选了6 那么就只能选4
{
prev[i]=i-2;
}
for(int i=2;i<N;i++)
{
opt[i]=max(opt[prev[i]]+array[i],opt[i-1]);//选或不选两种情况
}
printf("%d\n",opt[N-1]);
}
三、最长上升子序列
/*
5.最长上升子序列的长度
如:1 4 -3 -9 5 9 0
如:1,5,2,3,4,6,-5,-9,10,11
子序列 不要求连续,前后关系要和原序列一致
*/
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define N 10
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
//srand((int)time(0));
int a[N];
for(int i=0;i<N;i++)
{
a[i]=rand()%10;
}
for(int i=0;i<N;i++)
{
printf("%3d ",a[i]);
}
printf("\n");
//动态规划
int Lmax=1;
int d[N]; //记录当前元素的子序列长度
for(int i=0;i<N;i++)
{
d[i]=1; //假设当前元素的上升子序列只有自己 即长度为1;
for(int j=i-1;j>=0;j--)
{
if(a[i]>a[j])
{
//选自己的
d[i]=max(d[i],d[j]+1);//我的最优解等于我前面的比我小的元素的最优解+1
}
}
//和不选自己 Lmax
Lmax=max(Lmax,d[i]);
printf("%3d ",Lmax);
}
printf("最长上升子序列长度为:%d\n",Lmax);
}
四、三角形最短路径
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define N 4
int min(int a,int b)
{
return a>b?b:a;
}
int min_3(int a,int b,int c)
{
int t=c<(a<b?a:b)?c:(a<b?a:b);
return t;
}
int main(int argc,char* argv[])
{
int a[N][N],dp[N][N];
for(int i = 0;i<N;i++)
{
for(int j = 0;j<N;j++)
{
a[i][j]=-1;
}
}
srand((int)time(0));
//随机数种子
int k=2;
for(int i = 0;i<N;i++)
{
for(int j = 0;j<=i;j++)
{
a[i][j]=rand()%10+1; //随机赋值
}
}
for(int i = 0;i<N;i++)
{
for(int j = 0;j<=i;j++)
{
printf("%2d ",a[i][j]);
}
printf("\n");
}
/******************************/
dp[0][0]=a[0][0];
// printf("%d\n",dp[0][0]);
for(int i = 1;i<N;i++)
{
for(int j = 0;j<=i;j++)
{
if(j==0)//如果左边溢出
{
if(a[i-1][j+1]==-1)//右上边碰到墙壁只能取到上方
{
dp[i][j]=a[i][j]+dp[i-1][j];
}
else//右上没有碰到能取上方和右上方
{
dp[i][j]=min(dp[i-1][j],dp[i-1][j+1])+a[i][j];
}
}
else //左边不会溢出
{
if(a[i-1][j]==-1)//如果上边碰到只能取左上
{dp[i][j]=a[i][j]+dp[i-1][j-1];
}
else if(a[i-1][j+1]==-1)//右上边碰到 只能取到上方和上左
{
dp[i][j]=min(dp[i-1][j],dp[i-1][j-1])+a[i][j];
}
else //右边没有碰到能取到上面三个位置
{
dp[i][j]=min_3(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1])+a[i][j];
}
}
//printf("%d ",dp[i][j]);
}
//printf("\n");
}
int n_min;
n_min=dp[N-1][0];
for(int i=0;i<N;i++)
{
if(n_min >= dp[N-1][i])
{
n_min = dp[N-1][i];
}
//printf("%d ",dp[N-1][i]);
}
printf("%d \n",n_min);
return 0;
}