这周集训队对大一新生(好吧。马上大二了,要当学长了,可是学的不行,,长得也不行哎)的入门算法是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;
}