51nod 动态规划

基准时间限制:1 秒 空间限制:131072 KB 分值: 10 难度:2级算法题
 收藏
 关注
N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列)。当所给的整数均为负数时和为0。
例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。
 
Input
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数 (-10^9 <= S[i] <= 10^9)
Output
输出循环数组的最大子段和。
Input示例
6
-2
11
-4
13
-5
-2
Output示例
20

 1 #include<bits/stdc++.H>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 int a[100010];
 6 int n;
 7 const LL inf=1e17;
 8 int main()
 9 {
10     LL d=0;
11     scanf("%d",&n);
12     for(int i=0;i<n;i++) scanf("%d",&a[i]),d+=a[i];
13     LL sum=0;
14     LL ans1=-inf;
15     for(int i=0;i<n;i++)
16     {
17         sum+=a[i];
18         if(sum>ans1) ans1=sum;
19         if(sum<0) sum=0;
20     }
21 
22     sum=0;
23     LL ans2=inf;
24     for(int i=0;i<n;i++)
25     {
26         sum+=a[i];
27         if(sum<ans2) ans2=sum;
28         if(sum>0) sum=0;
29     }
30     printf("%lld\n",max(ans1,d-ans2));
31 }

循环数组的最大字段和,有两种状态,要么是从中间截取一段,不会跨越头尾;第二种是跨越头尾,在这种情况下,最大字段和应该是从序列中取出来一个最小字段和,然后用总的减掉即可

求最大字段和就是不断记录一个sum,用sum去更新ans

 

 

 

基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题
 收藏
 关注
N元钱换为零钱,有多少不同的换法?币值包括1 2 5分,1 2 5角,1 2 5 10 20 50 100元。
 
例如:5分钱换为零钱,有以下4种换法:
1、5个1分
2、1个2分3个1分
3、2个2分1个1分
4、1个5分
(由于结果可能会很大,输出Mod 10^9 + 7的结果)
Input
输入1个数N,N = 100表示1元钱。(1 <= N <= 100000)
Output
输出Mod 10^9 + 7的结果
Input示例
5
Output示例
4
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n;
 5 int v[20]={0,1,2,5,10,20,50,100,200,500,1000,2000,5000,10000};
 6 int dp[100010];
 7 const int mod=1e9+7;
 8 int main()
 9 {
10     scanf("%d",&n);
11     fill(dp,dp+n+1,1);
12     for(int i=2;i<=13;i++)
13     {
14         for(int j=v[i];j<=n;j++)
15         {
16             dp[j]=(dp[j]+dp[j-v[i]])%mod;
17         }
18 
19     }
20     printf("%d\n",dp[n]);
21 }

定义dp[i][j]为前i件物品,背包容量为j时,组合的方案数,那么dp[i][j]=sigma(dp[i-1][j-k*v[i]]),0<=k<=j/v[i],

化简方法:dp[i][j-v[i]]=sigma(dp[i-1][j-k*v[i]]),1<=k<=j/v[i]

那么 dp[i][j]=dp[i][j-v[i]]+dp[i-1][j]

滚动数组,从小到大递推

 

 

 

基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题
 收藏
 关注
平衡二叉树(AVL树),是指左右子树高度差至多为1的二叉树,并且该树的左右两个子树也均为AVL树。 现在问题来了,给定AVL树的节点个数n,求有多少种形态的AVL树恰好有n个节点。
Input
一行,包含一个整数n。 (0 < n <= 2000)
Output
一行表示结果,由于结果巨大,输出它对1000000007取余数的结果。
Input示例
10
Output示例
60
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 const int mod=1e9+7;
 6 
 7 int n;
 8 LL dp[2020][25];
 9 int main()
10 {
11     scanf("%d",&n);
12     dp[1][1]=1;
13     dp[0][0]=1;
14     for(int i=1;i<=n;i++)
15     {
16         for(int j=1;j<=20;j++)
17         {
18             LL tmp=0;
19             for(int k=0;k<=i-1;k++)
20             {
21                 cout<<j<<" "<<dp[k][j-2]<<endl;
22                 tmp=(tmp+dp[k][j-1]*dp[i-1-k][j-1]+dp[k][j-1]*dp[i-1-k][j-2]+dp[k][j-2]*dp[i-1-k][j-1])%mod;
23             }
24             dp[i][j]=tmp;
25         }
26     }
27     LL ans=0;
28     for(int i=1;i<=20;i++)
29         ans=(ans+dp[n][i])%mod;
30     printf("%lld\n",ans);
31 }

这里提交的是c++11标准,代码中可能访问-1下标,

n个节点的AVL树的种类数,定义状态dp[i][j]为节点数为i, j为高度 的形态的AVL树的种类数目,

那么dp[i][j] = dp[k][j-1] * dp[i-1-k][j-1] + dp[k][j-2] * dp[i-1-k][j-1] + dp[k][j-1]  * dp[i-1-k][j-2]  ,即为左右子树分类考虑的dp方式

初始化 dp[0][0]=1,dp[1][1]=1;

 

 

基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题
 收藏
 关注
编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
例如将kitten一字转成sitting:
sitten (k->s)
sittin (e->i)
sitting (->g)
所以kitten和sitting的编辑距离是3。俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。
给出两个字符串a,b,求a和b的编辑距离。
 
Input
第1行:字符串a(a的长度 <= 1000)。
第2行:字符串b(b的长度 <= 1000)。
Output
输出a和b的编辑距离
Input示例
kitten
sitting
Output示例
3

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int maxn=1010;
 5 char a[maxn];
 6 char b[maxn];
 7 int dp[maxn][maxn];
 8 
 9 int main()
10 {
11     scanf("%s%s",a+1,b+1);
12     int len1=strlen(a+1);
13     int len2=strlen(b+1);
14     int len=max(len1,len2);
15     for(int i=0;i<=len;i++) dp[i][0]=dp[0][i]=i;
16     for(int i=1;i<=len1;i++)
17     {
18         for(int j=1;j<=len2;j++)
19         {
20             dp[i][j]=min(dp[i][j-1],dp[i-1][j])+1;
21             if(a[i]!=b[j]) dp[i][j]=min(dp[i][j],dp[i-1][j-1]+1);
22             else dp[i][j]=min(dp[i][j],dp[i-1][j-1]);
23         }
24     }
25     printf("%d\n",dp[len1][len2]);
26 
27 }

 

要使得两个字符串变得相同,有替换 ,插入,删除三种操作,很显然拿两个指针分别在a/b串上走,

然后对ab所指向的字符 分别考虑是做什么操作,是替换还是插入删除

定义dp[i][j]为a中前i个与b中前j个变得相同 应该做多少操作

显然 dp[i][j] = min(dp[i-1][j],dp[i][j-1])+1;

再考虑 替换操作 if ( a[i]==b[j] ) dp[i][j] = dp[i-1][j-1];

       else dp[i][j] = dp[i-1][j-1] + 1;

posted @ 2017-08-14 10:17  TomJarry  阅读(157)  评论(0编辑  收藏  举报