算法笔记21.基础动态规划补充(全)

1.理想收入问题
现在已知楚继光手头有某只股票在过去几年中的价格,他试图据此模拟操作以获得理想收入。所谓理想收入是指在股票交易中,以1元为本金可能获得的最高收入,并且在理想收入中允许有非整数股票买卖。
  已知股票在第i天每股价格是 V[ i ]元,1 ≤ i ≤ n,求 n 天后的理想收入。
输入格式
  输入的第一行为 n (1 ≤ n ≤ 100 000)。下面有 n 个实数,依次为今后 n 天的股票价格。
这 n 个数可能分布在多行中。
输出格式
  对于给定的输入,输出 n 天后的理想输入(精确到 0.0001)。
输入样例
4
4.2 2.6
5.6 10.4
输出样例
4.0000

1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 using namespace std;
 5 const int size = 100005;
 6 
 7 double v[size], f[size];
 8 int main() {
 9     int n;
10     scanf("%d", &n);
11     for(int i = 1;i <= n;i++) {
12         scanf("%lf", &v[i]);
13         f[i] = 0;
14     }
15     /* f[i] = max{f[j] / v[k] * v[i]} (1 <= j < i, j < k <= i, f[0] = 1) */
16     f[0] = 1;
17     for(int i = 1;i <= n;i++) 
18         for(int j = 0;j < i;j++)
19             for(int k = j + 1;k <= i;k++) {
20                 f[i] = max(f[i], f[j] / v[k] * v[i]);
21             }
22     printf("%.4lf\n", f[n]);
23     return 0;    
24 } 

//朴素动态规划

2.数的划分问题

//f(i,j)表示把i分为j份数目
#include<iostream>
#define MAXSIZE 201
using namespace std;
int f[MAXSIZE][8],n,kind;
int main(){
	cin>>n>>kind;
	f[1][1] = 1;
	for(int i = 2;i<=n;i++)
	    for(int j=1;j<=kind;j++)
	      if(i>=j)
	      f[i][j] = f[i-1][j-1]+f[i-j][j];
	      cout<<f[n][kind]<<endl;
	return 0;
} 

其他类数的划分问题(很重要)
数的划分各类问题(divide)

3.硬币问题(hdu2844)
给n种硬币,面值Ai,数量Ci,能凑出多少种不大于m的面值。
样例输入:n m A C
3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0
样例输出:
8
4

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,m,a[105],c[105];
bool dp[100005];   //dp[i]表示价格i可以表示出来 
int ans[100005];   //ans[i]表示需要硬币数目 
int  main()
{
    while(scanf("%d%d",&n,&m)!=EOF&&(n!=0&&m!=0))
    {
        memset(dp,false,sizeof(dp));
        for(int i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
        }
        for(int i=0; i<n; i++)
        {
            scanf("%d",&c[i]);
        }
        dp[0]=true;
        for(int i=0; i<n; i++)
        {
            memset(ans,0,sizeof(ans));  //计数置零;
            for(int j=a[i]; j<=m; j++)
            {
                if(dp[j-a[i]]&&!dp[j]&&ans[j-a[i]]<c[i])  //把数量放在外边,优化了一个for循环;
                {
                    dp[j]=true;
                    ans[j]=ans[j-a[i]]+1;
                }
            }
        }
        int sum=0;
        for(int i=m; i>0; i--)
        {
            if(dp[i])
            {
                sum++;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

4.唱片录制问题
n首歌中取,发行m张唱片,每张唱片最多t分钟
唱片中的歌曲必须按创作顺序排序
m张唱片包含的歌曲越多越好

输入:
n m t
time1 time2 time3 …
输出
包含最多的歌曲数目

思路

//f[i,j]:前i首歌录了j首所需的最少唱片数
//g[i,j]:前i首歌录了j首当前唱片使用了多少容量
f[i,j]=min(f[i-1,j-1]+1,f[i-1,j])

如果第i首歌要录并且能录进当前唱片里

f[i,j]= f[i-1,j-1]

如果录不进,另开一张唱片

f[i,j]= f[i-1,j-1]

如果第i首歌不录,并且使用的唱片数小于第i首歌录进去的唱片数,自然不录,如果相等,选择当前唱片使用容量最少的方案,这样以后才能录更多。这里记得要保证i!=j(否则就变成前i-1首歌录了i首)。

#include <cstdio>
int n,m,c,a[1005],f[1005][1005],g[1005][1005];
const int inf=2147483647/4;
int main()
{
    int i,j;
    scanf("%d%d%d",&n,&m,&c);
    for (i=1;i<=n;i++)
      scanf("%d",&a[i]);
    for (i=1;i<=n;i++)
      for (j=1;j<=n;j++)
        f[i][j]=inf; 
    for (i=1;i<=n;i++)
      for (j=1;j<=i;j++)
      {
            if (g[i-1][j-1]+a[i]<=c)
              f[i][j]=f[i-1][j-1],
              g[i][j]=g[i-1][j-1]+a[i];
            else if (a[i]<=c)
              f[i][j]=f[i-1][j-1]+1,
              g[i][j]=a[i];
            if (i!=j && ((f[i-1][j]<f[i][j]) || (f[i-1][j]==f[i][j] && g[i-1][j]<g[i][j])))
              f[i][j]=f[i-1][j],
              g[i][j]=g[i-1][j];  
      }
    for (i=n;i>=1;i--)
      if (f[n][i]<m)
        break;
    printf("%d",i);      
    return 0;
}

5.双色马
N匹马,K个马厩,每一个马都只会是0或1,每一个马厩里会有一个不快乐值(不快乐值=0马的个数*1马的个数),问怎么分配会得出一个最小的不快乐值,输出最小的不快乐值。

#include<bits/stdc++.h>
using namespace std;
#define T 9999999
int main(){
	int f[501][501],a[501],s[501];
	//f[i][j] : i house,j horses 's min value
	//s[i]:to i's white horses' number
	//a[i]: record the 1 0 0 1
	int i,j,k,n,d;
	int Min;
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		f[0][i] = 0;
		f[i][0] = T;
		f[0][0] = 0;
	}
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=n;i++)
	{
		if(a[i]==1)
		s[i] = s[i-1]+1;
		else
		s[i] = s[i-1];
	}
	for(int j=1;j<=k;j++)
	for(int i=1;i<=n;i++)
	{
		Min = T;
		for(d=0;d<i;d++)
		if(Min>f[d][j-1]+(s[i]-s[d])*(i-d-(s[i]-s[d])))
		{
			Min = f[d][j-1] + (s[i]-s[d])*(i-d-(s[i]-s[d]));
			f[i][j] = Min;
		}
	}
	cout<<Min<<endl;
	return 0;
	
} 

6.选数统计问题
1至M中选出n个数:A1-An
要求每个数字至少为其前一项的两倍
例如n=4,M=10:
1 2 4 8
1 2 4 9
1 2 4 10
1 2 5 10
问一共可以选出多少不同的数列

分析:显然是构造dp,dp[i][j]表示长度为i,以j结尾的合法方案数。
则dp[i][j]=sum(dp[i-1][k])   k>0&&k<j&&j>2*k

代码:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
    int dp[15][505]={0};
    int n,m;
    cin>>n>>m;
    //dp[i][j]==dp[i-1][k] if(j==0&&j/k=2)
    int i,j,k;
    for(i=1;i<=m;i++)
        dp[1][i]=1;

    for(i=2;i<=n;i++)
        for(j=1;j<=m;j++)
            for(k=1;k<=j;k++)
                if(j>=2*k)
                    dp[i][j]+=dp[i-1][k];  
         int ans=0;
    for(i=1;i<=m;i++)
        ans+=dp[n][i];
    cout<<ans<<endl;
    return 0;
}

7.最大连续子序列和,k个最大连续子序列和(VIP)
我们用dp[n]表示以第n个数结尾的最大连续子序列的和,于是存在以下递推公式:
dp[n] = max(0, dp[n-1]) + num[n]
仔细思考后不难发现这个递推公式是正确的,则整个问题的答案是max(dp[m]) | m∈[1, N]

#include <stdio.h>

//N是数组长度,num是待计算的数组,放在全局区是因为可以开很大的数组
int N, num[134217728];

int main()
{
    //输入数据
    scanf("%d", &N);
    for(int i = 1; i <= N; i++)
        scanf("%d", &num[i]);
    
    num[0] = 0;
    int ans = num[1];
    for(int i = 1; i <= N; i++) {
        if(num[i - 1] > 0) num[i] += num[i - 1];
        else num[i] += 0;
        if(num[i] > ans) ans = num[i];
    }

    printf("%d\n", ans);

    return 0;
}

k个最大连续子序列和,子序列不相交
例如
n=10,k=2
-1 1 -2 3 4 -2 -5 5 6 7
那么:
3 4
5 6 7
是两个连续子序列
7+18 =
25
解决思路:

f[i][j]:数列前j个元素中,i个无公共元素的子序列的最大和
且子序列必须包含第j个元素
状态转移方程:
f[i][j] = max{f[i][j-1]+a[j] , f[i-1][k]+a[j]}
i-1=<k<=j-1

代码:

自己写

8.最长公共上升子序列问题
直接阅读

9.购物问题1
zoj1524
题解

10.购物问题2
zoj1563
题解

11.机器分配问题
值得一看

12.系统可靠性
可以一看

13.邮局问题(VIP+PKU1160)
PKU1160

14.调度问题
作为练习
题目源

15.zipper
作为练习
POJ2192
题目源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《算法笔记》是一本由胡凡撰写的计算机科学书籍,该书主要介绍了一些常见的算法和数据结构,并且给出了相应的代码实现。 胡凡的代码非常简洁清晰,注释详细。他的代码实现旨在提供读者一个易于理解和实现的参考模板,以提高读者对算法和数据结构的理解和应用能力。 《算法笔记》的代码实现涵盖了众多经典的算法和数据结构,如排序算法、图算法动态规划等。通过学习这些代码,读者可以更好地理解算法的思想和设计方法。 此外,胡凡的代码实现还包括一些实际应用的案例,这使得读者能够将所学的算法和数据结构应用到自己的项目。通过实际的案例,读者可以进一步加深对算法的认识,并学会如何将算法应用到实际问题解决。 总的来说,胡凡的代码实现非常有参考价值,对于算法和数据结构的学习和应用都具有很大的帮助。他的代码简洁清晰,容易理解和实现,是学习算法的一本不可多得的好书。 ### 回答2: 《算法笔记》是由胡凡编写的一本关于算法的学习资料。这本书主要介绍了算法的基本概念、常见的算法思想和常用的算法模板。胡凡是一位算法领域的专家,他将自己多年的学习和研究经验融入其,旨在帮助读者更好地理解算法的本质和应用。 在《算法笔记,胡凡通过清晰明确的语言和丰富多样的示例,向读者介绍了常见的排序算法、查找算法、图算法等等。同时,他还特别强调了算法的时间复杂度和空间复杂度分析的重要性,以及如何通过优化算法提升程序的效率。这对于想要提高编程水平的读者来说是非常有价值的。 胡凡的代码也是《算法笔记》的重要内容之一。他以Python为主要编程语言,用简洁而易懂的代码实现了书介绍的各种算法。这些代码通常具有较高的复用性和可读性,既能够帮助读者理解算法的具体实现逻辑,也可以作为实际项目的参考代码。 总之,《算法笔记》是一本很好的算法学习资料,它通过详细的讲解和清晰的代码示例,帮助读者建立了对算法的深入理解。无论是初学者还是有一定经验的程序员,都可以从获得很多有价值的知识和技巧。通过不断地学习和实践,读者可以在编程灵活应用这些算法,提高自己的编程水平。 ### 回答3: 《算法笔记》是一本非常经典的算法教材,由胡凡和曾磊合著。书详细介绍了各种常见的算法及其实现方法,对算法的思想和原理进行了深入剖析,为读者提供了面的学习指南。 在《算法笔记,作者以清晰的逻辑和简洁的代码,让读者了解算法设计的基本原则和常见的解题思路。胡凡的代码是书的重要组成部分,通过实例和案例,读者可以深入理解算法的实际应用,同时也能掌握用代码实现各种算法的技巧。 胡凡的代码非常精炼和高效,他在编写代码时注重算法的时间和空间复杂度,以求得最优解。无论是经典算法的实现,如排序算法、贪心算法,还是动态规划、图算法等高级算法,胡凡的代码都能给读者带来很多启发和思考。 此外,胡凡的代码还注重代码复用和模块化设计,他通过定义适当的数据结构和函数,使得代码结构清晰,易于理解和修改。这有助于读者在实际项目灵活运用算法,并提高编码的质量和效率。 总之,《算法笔记胡凡的代码是一道亮丽的风景线,它不仅仅是学习算法的工具,更是一本智慧的结晶。通过学习胡凡的代码,读者可以提升自己的算法水平,拓宽思维的广度和深度,从而在日后的工作和学习取得更好的成果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值