入门DP专练

   这周集训队对大一新生(好吧。马上大二了,要当学长了,可是学的不行,,长得也不行哎)的入门算法是DP,其实在此之前也做过一些动态规划方面的题目,但是DP类的题目真的是变化多,想要掌握还真是不行,更别说应用自如了,曾经Baka哥(wode超级偶像奥害羞)就说要多多做题,见得种类多了,也就慢慢的有感觉了,我现在别说有感觉,除了明显的背包问题外,基本根本没法看出这是要用DP.可是快要期末考试了,集训还是并没有一点点停歇,看的出来学校对我们这届重视了,这是个好消息,不希望学校的ACM一直这么弱。这周周末就要4级了,也不知裸考的我能不能过,算了,走一步算一步了。

学动规的时候有这么一句话,现在摘抄下:如果各个子问题不是独立的,不同的子问题的个数只是多项式量级,如果我们能够保存已经解决的子问题的答案,而在需要的时候再找出以求的答案,这样可以避免不必要的大量重复,此时需要考虑动规。

HDU 1058 Humble Numbers

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1058

题意:是说如果一个数的素因子只有2,3,5,7,则被称为humber numbers。计算第n个humble number(一下简称HN)。这道题还有一个对第几的表示,主要考虑特殊考虑1,2,3,11,12,13及余数为1,2,3的数即可。

可以这么考虑,当一个数为HN时,他的倍数也为HN。

状态转移方程:dp[i]=min(dp[a2]*2,dp[a3]*3,dp[a5]*5,dp[a7]*7).由于要按照顺序,所以方程要保证位置是目前状态最小的。同时要避免重复,在打表时还的注意下。

代码:

#include <stdio.h>
#include <algorithm>
using std::min;

int dp[5845];//dp[i]表示第i个数
char word[3][3]={"st","nd","rd"};

void judge()
{
	int a2,a3,a5,a7;
	dp[1]=1;
	a2=a3=a5=a7=1;

	int temp,i=2;
	while(i<5845)
	{
		temp=min(min(dp[a2]*2,dp[a3]*3),min(dp[a5]*5,dp[a7]*7));

		if(temp==dp[a2]*2)
			a2++;
		else if(temp==dp[a3]*3)
			a3++;
		else if(temp==dp[a5]*5)
			a5++;
		else if(temp==dp[a7]*7)
			a7++;
		if(temp>dp[i-1])//防止重复
		{
			dp[i]=temp;
		    i++;
		}
	}
}

int main()
{
	//freopen("in.txt","r",stdin);
	int n;
	judge();
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0)
			break;
		printf("The %d",n);

		if(n%100==11||n%100==12||n%100==13)
		printf("th humble number is %d.\n",dp[n]);
		else if(n%10==1||n%10==2||n%10==3)
			printf("%s humble number is %d.\n",word[n%10-1],dp[n]);
		else 
			printf("th humble number is %d.\n",dp[n]);
	}
	return 0;
}




HDU 1087 Super Jumping!Jumping!Jumping!

链接:http://acm.hdu.edu.cn/showproblem.php?pid=1087

分析:求最长上升子序列,如果要跳到下一个位置的话,下一个数必须比当前的数大。要求从前往后跳,则状态转移方程:dp[i]=max[dp[i],dp[j]+a[i]);要求a[i]>a[j]&&j<i ,同时要注意初始化(dp[i]=a[i])。

代码:

#include<stdio.h>
int main()
{
	int a[1000],dp[1000],i,n,j,max;
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0)
			break;
		for(i=0;i<n;i++)
		{
			scanf("%d",a+i);
			dp[i]=a[i];
		}
		max=0;
		for(i=0;i<n;i++)
		{
			for(j=0;j<i;j++)
				if(a[j]<a[i])
				{
					if(dp[j]+a[i]>dp[i])
						dp[i]=dp[j]+a[i];
				}
		  if(dp[i]>max)
			max=dp[i];
		}
		printf("%d\n",max);
	}
	return 0;
}	


 


 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值