前言:我们队的dp一直是我在做,说不上做的很顺,有些可以做,有些不能做。到现在为止,做dp题目也有七八十道了,除了背包问题的题目我可以说有百分之七八十的把握ac的话,其他类型的dp,还真没有多大把握。越是做dp题,就越是发现dp的博大精深,我想,dp这个专题,对于我这样的人来说,做上两百道,才能真正有所把握.........

25道dp题题目:

1.hdu  1503

题意:给你两个字符串,要你用这两个字符串组成这样一个字符串,在组成的字符串中字符的相对顺序不变的情况下,可以在组成的字符串中找到原先两个字符串,字母可以错开,但是相对顺序不能变化,要这个组成的字符串中字母数最少,并输出这个字符串。

Sample Input
apple peach
ananas banana
pear peach
 
Sample Output
appleach
bananas
pearch
 
思路:这是一道最长公共子序列的题目,当然还需要记录路径。把两个字符串的最长公共字串记录下来,在递归回溯输出的时候,要是两个字符是公共子串,就只输出一次,要不是,就分别把位于相同位置的两个字符串的字符输出.......
代码:
 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[][],vist[][];
char s[],t[];
void print(int x,int y)
{
if(x==&&y==)
return;
if(vist[x][y]==)
{
print(x-,y-);
printf("%c",t[y-]);
}
else if(vist[x][y]==)
{
print(x-,y);
printf("%c",s[x-]);
}
else if(vist[x][y]==)
{
print(x,y-);
printf("%c",t[y-]);
}
else if(vist[x][y]==&&y==&&x>)
{
print(x-,y);
printf("%c",s[x-]);
}
else if(vist[x][y]==&&x==&&y>)
{
print(x,y-);
printf("%c",t[y-]);
}
}
int main()
{
while(scanf("%s%s",s,t)>)
{
int lens=strlen(s),lent=strlen(t);
for(int i=;i<;i++)
dp[][i]=dp[i][]=;
memset(vist,,sizeof(vist));
for(int i=;i<=lens;i++)
{
for(int j=;j<=lent;j++)
if(s[i-]==t[j-])
{
dp[i][j]=dp[i-][j-]+;
vist[i][j]=;
} else
{
int maxx=;
if(dp[i][j-]<dp[i-][j])
{
dp[i][j]=dp[i-][j];
vist[i][j]=;
}
else
{
dp[i][j]=dp[i][j-];
vist[i][j]=;
}
}
}
int i=lens,j=lent,cnt=;
//printf("111\n");
print(lens,lent);
printf("\n");
}
return ;
}

2、hdu 1502

题意:给你A,B,C三种字母,问你,当有n个A,n个B,n个C的时候,满足组成的字符串的所有前缀A的个数大于等于B的个数大于等于C的个数,并B的个数大于等于C的个数有多少个?

Sample Input
2
3
Sample Output
5
42
思路:这道dp题的转移方程是dp[i][j][k]=dp[i-1][j][k]+dp[i][j-1][k]+dp[i][j][k-1];(i>j>k)
当然,我是用记忆化搜索+打表过的,在记忆化搜索里面写大数的加法,然后打个表,就出结果了。
打表是一种神器,不要小看它........
记忆化搜索代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[][][][],n;
void dfs(int x,int y,int z,int w)
{
int i=;
while(dp[x][y][z][i]==) i++;
if(i<=)
{
//printf("%d %d\n",dp[x1][y1][z1][20],dp[x][y][z][20]);
return;
}
if(x<y) return;
if(x<z) return;
if(y<z) return;
if(x<n)
{
dfs(x+,y,z,);
int i=;
while(dp[x+][y][z][i]==) i++;
if(i<=)
{
//printf("%d %d %d\n",x,y,z);
for(int j=;j>;j--)
{
dp[x][y][z][j]+=dp[x+][y][z][j];
if(dp[x][y][z][j]/>)
{
dp[x][y][z][j-]+=dp[x][y][z][j]/;
dp[x][y][z][j]%=;
}
}
}
} if(y<n)
{
dfs(x,y+,z,);
int i=;
while(dp[x][y+][z][i]==) i++;
if(i<=)
{
//printf("%d %d %d\n",x,y,z);
for(int j=;j>;j--)
{
dp[x][y][z][j]+=dp[x][y+][z][j];
if(dp[x][y][z][j]/>)
{
dp[x][y][z][j-]+=dp[x][y][z][j]/;
dp[x][y][z][j]%=;
}
}
}
} if(z<n)
{
dfs(x,y,z+,);
int i=;
while(dp[x][y][z+][i]==) i++;
if(i<=)
{
//printf("%d %d %d\n",x,y,z);
for(int j=;j>;j--)
{
dp[x][y][z][j]+=dp[x][y][z+][j];
if(dp[x][y][z][j]/>)
{
dp[x][y][z][j-]+=dp[x][y][z][j]/;
dp[x][y][z][j]%=;
}
}
}
} }
int main()
{
//n=60;
//memset(dp,0,sizeof(dp));
//dp[60][60][60][20]=1;
//dfs(0,0,0,0);
n=;
while(scanf("%d",&n)>)
{
int i=;
memset(dp,,sizeof(dp));
dp[n][n][n][]=;
dfs(,,,);
while(dp[][][][i]==) i++;
printf("%c",'"');
printf("%d",dp[][][][i]);
i++;
while(i<)
{
printf("%05d",dp[][][][i]);
i++;
}
if(i==)
{
printf("%05d",dp[][][][i]);
} printf("%c",'"');
printf(",");
printf("\n");
dp[n][n][n][]=;
n++;
}
return ;
}

打表代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
char s[][]={
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
};
int main()
{
int n;
while(scanf("%d",&n)>)
{
printf("%s\n\n",s[n]);
}
return ;
}

3、hdu3008

题意:需要打一只boss,小明和boss都是每秒攻击一次,但是是小明先攻击boss。小明和boss的血量都是100,小明的普通攻击为1,当然除了普通攻击外,小明还有魔法攻击,小明的魔法量也是100,每次魔法攻击都需要扣除一定量的魔法值,boss的攻击力是固定的为q,小明有n种魔法技能,在小明每次攻击之后会回复t点魔法值,每种魔法技能伤害为bi,耗费魔法值为ai,然后问小明打死boss所要用的最少时间,当然如果小明不能打死boss,输出My god

思路:dp[i][j]代表着小明第i次攻击,还剩下j点魔法值的情况下打掉的boss血量,

dp[i][j]=max(dp[i-1][j-t]+1,dp[i-1][j+s[k][0]-t]+s[k][1]);

当然,这只是一个粗略的转移方程,其中的魔法值不超过100,等等细节还需处理好

代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[][];
struct node
{
int x,y;
}s[];
int cmp(const node a,const node b)
{
if((double)a.x/(double)a.y>(double)b.x/(double)b.y)
return ;
else
return ;
}
int main()
{
int n,p,t;
while(scanf("%d%d%d",&n,&p,&t)>&&(n+p+t))
{
for(int i=;i<=n;i++)
scanf("%d%d",&s[i].x,&s[i].y);
//sort(s+1,s+1+n,cmp);
memset(dp,,sizeof(dp));
dp[][]=;
s[].x=; //把普通攻击也算成一种魔法攻击
s[].y=;
int flag=;
int tmp=/t; //算出小明最多可以攻击的次数
if(%t>)
tmp++;
//printf("%d\n",tmp);
int cnt=;
for(int i=;i<=tmp;i++)
{
for(int j=;j<=n;j++)
{
for(int k=;k>=s[j].x;k--)
{
int ans=k-s[j].x+p;
if(ans>)
ans=;
if(dp[i-][k]+s[j].y>dp[i][ans])
dp[i][ans]=dp[i-][k]+s[j].y;
// printf("%d %d %d\n",dp[i][ans],s[i].x,s[i].y);
if(dp[i][ans]>=)
{
flag=;
cnt=i;
break;
}
}
if(flag)
break;
}
if(flag)
break;
}
if(flag==)
printf("My god\n");
else
printf("%d\n",cnt);
//printf("%d\n",dp[100][i]);
}
return ;
}

4、hdu1501

题意:给你三个单词,在前两个单词相对顺序不变的情况下,是否能组成第三个单词?第三个单词的长度是前两个单词的长度和

思路:普通搜索和记忆化搜索都是可以的,主要是要剪枝,判断第三个单词的最后一个字母是否由前两个单词的最后一个字母组成......

代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
char s[][],dp[];
int len1,len2,len0,flag=;
int dfs(int num0,int num1,int num2)
{
//printf("1111\n");
if(dp[num2]>)
return ;
if(num1>=len1&&num0>=len0)
return ;
if(num0==len0&&s[][num1]!=s[][num2])
return ;
if(num1==len1&&s[][num0]!=s[][num2])
return ;
if(s[][num0]!=s[][num2]&&s[][num1]!=s[][num2])
return ;
if(num0<len0&&s[][num0]==s[][num2])
{
dp[num2]=dfs(num0+,num1,num2+);
}
if(num1<len1&&s[][num1]==s[][num2])
{
dp[num2]=dfs(num0,num1+,num2+);
}
return dp[num2];
}
int main()
{
int text,f=;
scanf("%d",&text);
while(text--)
{
scanf("%s%s%s",s[],s[],s[]);
len0=strlen(s[]);
len1=strlen(s[]);
len2=strlen(s[]);
flag=;
memset(dp,,sizeof(dp));
dp[len2]=;
if(len0+len1>=len2&&(s[][len0-]==s[][len2-]||s[][len1-]==s[][len2-]))
flag=dfs(,,);
printf("Data set %d: ",++f);
if(flag==)
printf("yes\n");
else
printf("no\n");
}
return ;
}

5、hdu1300

题意:有n种珠宝,每种珠宝有其等级,现在按照珠宝的等级从低到高给出,每种珠宝需要买的数量,以及珠宝的价格。每买一种珠宝,就必须多买额外10串这种珠宝,当然可以买高等级的珠宝来代替低等级的,这样就只需额外的买10串高等级的珠宝,求最少的价值。

思路:由于已经按照等级排好序,那么dp[i]代表买i种等级的珠宝所用的最少价值。那么dp[i]=min{dp[i-1]+(s[i][0]+10)*s[i][1],dp[j]+(sum[i]-sum[j]+10)*s[i][1]}(1<=k<i)

代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[],t[],s[][],cont[];
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
int n;
scanf("%d",&n);
cont[]=;
for(int i=;i<=n;i++)
{
scanf("%d%d",&s[i][],&s[i][]);
cont[i]=cont[i-]+s[i][];
}
dp[]=;
for(int i=;i<=n;i++)
{
dp[i]=dp[i-]+(s[i][]+)*s[i][];
int minx=;
for(int j=;j<i;j++)
{
int tmp=dp[j]+(cont[i]-cont[j]+)*s[i][];
if(tmp<minx)
minx=tmp;
}
if(dp[i]>minx)
dp[i]=minx;
}
printf("%d\n",dp[n]);
}
return ;
}

6、hdu1422(水题)

7、hdu1224

题意:给你n+1个点,其中1是起点,同时n+1是终点,终点和起点是同一个点,飞机只能从编号小的点飞到编号大的点,每个编号都有愉快值,求能从起点飞到终点的最大愉快值。

思路:dp[i]=max(dp[j])+s[i];(j<i)

 #include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int dp[],vist[][],a[],path[],n;
void print(int num)
{
if(num==)
return;
if(path[num]!=)
{
print(path[num]);
}
if(num!=n+)
printf("%d->",num);
}
int main()
{
int text,p=;
scanf("%d",&text);
while(text--)
{
//int n;
scanf("%d",&n);
memset(a,,sizeof(a));
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
int m;
scanf("%d",&m);
memset(vist,,sizeof(vist));
memset(dp,,sizeof(dp));
dp[]=;
for(int i=;i<=m;i++)
{
int tmp1,tmp2;
scanf("%d%d",&tmp1,&tmp2);
if(tmp1>tmp2)
swap(tmp1,tmp2);
vist[tmp1][tmp2]=;
}
memset(path,,sizeof(path));
int maxn=,k=-;
for(int i=;i<=n+;i++)
{
int maxp=-;
for(int j=;j<i;j++)
{
if(dp[j]!=&&vist[j][i]!=&&maxp<dp[j])
{
maxp=dp[j];
path[i]=j;
}
}
if(maxp>dp[i])
dp[i]=maxp+a[i];
if(dp[i]>maxn)
{
maxn=dp[i];
k=i;
}
}
printf("CASE %d#\n",++p); printf("points : %d\n",dp[n+]-); printf("circuit : "); print(n+);
printf("1\n");
if(text)
printf("\n");
}
return ;
}

8、hdu1074
这是道状态压缩dp,我打算放在状态压缩dp里面再详细说说

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
struct node
{
int pre;
int cost;
int num;
}dp[];
struct node1
{
char name[];
int cost;
int qx;
}s[];
bool vist[];
void print(int x)
{
int tmp=x,k=;
tmp=x^dp[x].pre;
tmp=tmp>>;
//printf("%d\n",tmp);
while(tmp)
{
k++;
tmp=tmp>>;
//printf("%d\n",tmp);
}
if(dp[x].pre!=)
{
print(dp[x].pre);
}
printf("%s\n",s[k].name);
}
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
int n;
scanf("%d",&n);
for(int i=;i<n;i++)
scanf("%s%d%d",s[i].name,&s[i].qx,&s[i].cost);
int m=<<n;
dp[].pre=-;
dp[].cost=;
dp[].num=;
memset(vist,false,sizeof(vist));
vist[]=true;
for(int i=;i<m-;i++)
{
for(int j=;j<n;j++)
{
int tmp=<<j;
if((tmp&i)==)
{
int tmp1=tmp|i;
dp[tmp1].cost=dp[i].cost+s[j].cost;
int r=dp[tmp1].cost-s[j].qx;
if(r<)
r=;
r=r+dp[i].num;
if(!vist[tmp1])
{
vist[tmp1]=true;
dp[tmp1].num=r;
dp[tmp1].pre=i;
}
else if(dp[tmp1].num>r)
{
dp[tmp1].num=r;
dp[tmp1].pre=i;
}
}
}
}
printf("%d\n",dp[m-].num);
print(m-);
}
return ;
}

9、hdu1080(带权值的最长公共子序列问题)

题意:给你两串字符,要你求这两字符的最大匹配值。每个字符与其他字符匹配,都有一个权值,权值表已经给出,输入输出中,只有这么几种字符,可以用空格代替字符。

思路:变形的最长公共子序列。

反思:我以前一直认为最长公共子序列就是哥模板,顶多再来个记录路径,没有想到,这次是它的变形。其实做题目,最好的就是做变形题,这样可以开拓自己的思路......

在最长公共子序列中,dp[i][j]代表的是字符串s前i-1个字符与字符串t钱j-1个字符的最大匹配数,所以,当s[i-1]与t[i-1]匹配的时候,取dp[i-1][j-1]+1;当s[i-1]与

t[j-1]不匹配的时候,我们取dp[i-1][j],dp[i][j-1]的最大值,dp[i-1][j]代表着s串中长度为i-2的字符与t串中长度为j-1的字符匹配的最大长度。

如此,这个题目带权值,那么

dp[i][j]代表的是,字符串s前i-1个字符与字符串t钱j-1个字符匹配的最大权值,那么当我们让s[i-1]与t[j-1]匹配的时候(这两个字符不一定要相等,只是需要匹配的权值),可以匹配上的话,dp[i][j]=dp[i-1][j-1]+匹配上的权值;

若是不能匹配的话,dp[i][j]有两种情况,dp[i][j]=dp[i-1][j]+s串中第i-1个字符与t串中空格所匹配的权值........下面那个也是同理

代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define M -1000000000
int dp[][];
char s[],t[];
int find(char ch)
{
if(ch=='A')
return ;
if(ch=='C')
return ;
if(ch=='G')
return ;
if(ch=='T')
return ;
if(ch=='-')
return ;
}
int main()
{
int text;
scanf("%d",&text);
int a[][]={
,-,-,-,-,
-,,-,-,-,
-,-,,-,-,
-,-,-,,-,
-,-,-,-,M,
};
while(text--)
{
int lens,lent;
scanf("%d %s",&lens,s);
scanf("%d %s",&lent,t);
dp[][]=;
for(int i=;i<=lens;i++)
dp[i][]=a[find(s[i-])][find('-')]+dp[i-][];
for(int i=;i<=lent;i++)
dp[][i]=a[find('-')][find(t[i-])]+dp[][i-];
for(int i=;i<=lens;i++)
{
for(int j=;j<=lent;j++)
{
dp[i][j]=dp[i-][j-]+a[find(s[i-])][find(t[j-])];
dp[i][j]=max(dp[i][j],dp[i][j-]+a[find('-')][find(t[j-])]);
dp[i][j]=max(dp[i][j],dp[i-][j]+a[find(s[i-])][find('-')]);
}
}
printf("%d\n",dp[lens][lent]);
}
return ;
}

10、hdu1059(背包问题,在背包总结有详细解答)

11、hdu1158

题意:经理有三种操作,雇佣一个人,支付它工资,开除一个人,这三种操作的花费分别为a,b,c,然后每个月经理需要si个人做事,问n个月后,经理的最小花费。

思路:dp[i][j]代表第i天有j个人时的最小花费。

dp[i][j]=min(dp[i-1][k]+abs(j-k)*(a (or) c)+j*b)(s[i-1]<=k<=maxn);其中,maxn为要雇佣的最大人数

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[][],s[];
int main()
{
int n;
while(scanf("%d",&n)>&&n)
{
int a,b,c,maxn=;
scanf("%d%d%d",&a,&b,&c);
for(int i=;i<=n;i++)
{
scanf("%d",&s[i]);
if(maxn<s[i])
maxn=s[i];
}
for(int i=;i<=maxn;i++) //第一天的花费是可以确定的
dp[][i]=i*(a+b);
for(int i=;i<=n;i++)
{
for(int j=s[i];j<=maxn;j++)
{
dp[i][j]=<<; //赋值为最大
for(int k=s[i-];k<=maxn;k++)
{
int cost;
if(k<j)
cost=j*b+(j-k)*a;
else
cost=j*b+(k-j)*c;
dp[i][j]=min(dp[i][j],dp[i-][k]+cost);
}
}
}
int minx=dp[n][maxn];
for(int i=s[n];i<=maxn;i++)
if(minx>dp[n][i])
minx=dp[n][i];
printf("%d\n",minx);
}
return ;
}

12、hdu2059(水)

13、hdu1081(最长递增子序列变形)

题意:给你一些带权值的点组成的矩形,要你在这个矩形内找一个子矩形,使得这个子矩形内的点加起来权值最大......

As an example, the maximal sub-rectangle of the array:
0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:
9 2
-4 1
-1 8

思路:这其实就是一个二维的最长递增子序列......我们只需要把二维压缩成以为就好......

代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int s[][],t[];
int main()
{
int n;
while(scanf("%d",&n)>)
{
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
scanf("%d",&s[i][j]);
}
int maxx=-,sum;
for(int i=;i<=n;i++)
{
memset(t,,sizeof(t));
for(int j=i;j<=n;j++)
{
for(int k=;k<=n;k++)
{
t[k]+=s[j][k];
}
sum=;
for(int p=;p<=n;p++)
{
sum+=t[p];
if(sum<)
sum=;
if(sum>maxx)
maxx=sum;
}
if(maxx<sum)
maxx=sum;
}
}
printf("%d\n",maxx);
}
return ;
}

14、hdu1078(水)

解题报告:http://www.cnblogs.com/ziyi--caolu/p/3197714.html

15、hdu1025(最长递增子序列模板?.....忘了,反正比较水)

代码O(nlongn):

 #include<iostream>
#include<stdio.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct node
{
int a,b;
}s[];
int cmp(const node p,const node q)
{
if(p.a<q.a)
return ;
else if(p.a==q.a&&p.b<q.b)
return ;
else
return ;
}
int dp[];
int main()
{
int n;
int text=;
//scanf("%d",&text);
while(scanf("%d",&n)>)
{ for(int i=;i<n;i++)
scanf("%d%d",&s[i].a,&s[i].b);
sort(s,s+n,cmp);
dp[]=s[].b;
int len=;
for(int i=;i<n;i++)
{
int left=,right=len-,mid;
if(dp[len-]<s[i].b)
dp[len++]=s[i].b;
else
{
right=len-;
while(left<=right)
{
mid=(left+right)/;
if(dp[mid]<s[i].b)
left=mid+;
else right=mid-;
}
dp[left]=s[i].b;
}
}
printf("Case %d:\n",++text);
if(len==)
printf("My king, at most %d road can be built.\n\n",len);
else
printf("My king, at most %d roads can be built.\n\n",len);
}
return ;
}

16、hdu1160(赤裸裸的最长递增子序列,模板题)

17、hdu1024(很明显的最大m字段和问题)

题意:给你一个m,一个n,后面跟n个数,要你把这n个数分成m段,m段加起来的和最大.....求最大和

思路:这个题目应当算作区间dp的,只是看到了,就将它ac了吧。dp[i][j]表示将前i个数分为j段的最大和

那么dp[i][j]=max{dp[i-1][j]+a[i],max(dp[k][j-1])+a[i]}其中k>=1,k<i;

再开一个数组来记录max(dp[k][j-1])就ok.......当然,这个题目还需要将二维压缩成一维.....

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
typedef __int64 ss;
#define minx -100000000
ss dp[],f[],a[];
int main()
{
ss n,m;
while(scanf("%I64d%I64d",&m,&n)>)
{
for(int i=;i<=n;i++)
{
scanf("%I64d",&a[i]);
dp[i]=f[i]=;
}
dp[]=f[]=;
ss maxn;
for(int i=;i<=m;i++)
{
maxn=minx;
for(int j=i;j<=n;j++)
{
dp[j]=max(dp[j-],f[j-])+a[j];
f[j-]=maxn;
if(maxn<dp[j])
maxn=dp[j];
}
}
printf("%I64d\n",maxn);
}
return ;
}

18、hdu1114(背包水题)

19、hdu2191(背包水题)

20、hdu1978(记忆化搜索水题)

21、hdu1789(贪心)

22、hdu1058(经典dp)

题意:

A number whose only prime factors are 2,3,5 or 7 is called a humble number. The sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, ... shows the first 20 humble numbers.
Write a program to find and print the nth element in this sequence
思路:它的经典在于用n个变量去处理多种结果,这个在我以前的思维中是没有的
代码:

 #include<iostream>
using namespace std;
typedef __int64 ss;
int min(int x,int y,int j,int k)
{
int min1,min2;
if(x>y)
min1=y;
else
min1=x;
if(j>k)
min2=k;
else
min2=j;
return (min1>min2? min2:min1);
}
int main()
{
ss dp[],j,m,n,k,i;
dp[]=;
j=m=n=k=;
i=;
while(i<)
{
dp[i]=min(dp[j]*,dp[m]*,dp[n]*,dp[k]*);
if(dp[i]==dp[j]*)
j++;
if(dp[i]==dp[m]*)
m++;
if(dp[i]==dp[n]*)
n++;
if(dp[i]==dp[k]*)
k++;
i++;
}
while(scanf("%I64d",&n)>&&n)
{
ss r=n%;
ss f=n%;
if(r==&&f!=)
printf("The %I64dst humble number is %I64d.\n",n,dp[n]);
else if(r==&&f!=)
printf("The %I64dnd humble number is %I64d.\n",n,dp[n]);
else if(r==&&f!=)
printf("The %I64drd humble number is %I64d.\n",n,dp[n]);
else
printf("The %I64dth humble number is %I64d.\n",n,dp[n]);
}
return ;
}

23、hdu1421

题意:

搬寝室是很累的,xhd深有体会.时间追述2006年7月9号,那天xhd迫于无奈要从27号楼搬到3号楼,因为10号要封楼了.看着寝室里的n件物品,xhd开始发呆,因为n是一个小于2000的整数,实在是太多了,于是xhd决定随便搬2*k件过去就行了.但还是会很累,因为2*k也不小是一个不大于n的整数.幸运的是xhd根据多年的搬东西的经验发现每搬一次的疲劳度是和左右手的物品的重量差的平方成正比(这里补充一句,xhd每次搬两件东西,左手一件右手一件).例如xhd左手拿重量为3的物品,右手拿重量为6的物品,则他搬完这次的疲劳度为(6-3)^2 = 9.现在可怜的xhd希望知道搬完这2*k件物品后的最佳状态是怎样的(也就是最低的疲劳度),请告诉他吧.
 
思路:对物品的重量排序之后,dp[i][j]代表在i件物品中拿j对物品的最小疲劳度
dp[i][j]=min(dp[i-1][j],dp[i-2][j-1]+(a[i]-a[i-1])*(a[i]-a[i-1]));
代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int dp[][],a[];
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)>)
{
for(int i=;i<=n;i++)
scanf("%d",&a[i]);
sort(a+,a++n);
for(int i=;i<=n;i++)
for(int j=;j<=k;j++)
dp[i][j]=;
for(int i=;i<=n;i++)
dp[i][]=;
for(int i=;i<=n;i++)
{
for(int j=;j<=i/&&j<=k;j++)
dp[i][j]=min(dp[i-][j-]+(a[i]-a[i-])*(a[i]-a[i-]),dp[i-][j]);
}
printf("%d\n",dp[n][k]);
}
return ;
}

24、hdu1159(最长公共子序列模板题)

25、hdu1257(贪心或最长递增子序列)

26、hdu1244

题意:

给定一个由n个正整数组成的整数序列
a1 a2 a3 ... an
求按先后次序在其中取m段长度分别为l1、l2、l3...lm的不交叠的连续整数的和的最大值。
 
思路:dp[i][j]表示在前i个元素中取j段的和的最大值。那么dp[i][j]=max{dp[i-1][j],dp[i-a[j]][j-1]+sum[i]-sum[i-a[j]]};
代码:

 #include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int dp[][],a[],sum[],s[];
int main()
{
int n;
while(scanf("%d",&n)>&&n)
{
int m;
scanf("%d",&m);
for(int i=;i<=m;i++)
scanf("%d",&s[i]);
memset(dp,,sizeof(dp));
sum[]=;
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-]+a[i];
}
int ans=;
for(int j=;j<=m;j++)
{
ans+=s[j];
for(int i=ans;i<=n;i++)
{
dp[i][j]=max(dp[i-][j],dp[i-s[j]][j-]+sum[i]-sum[i-s[j]]);
}
}
printf("%d\n",dp[n][m]);
}
return ;
}

hdu26道动态规划总结的更多相关文章

  1. 338. Counting Bits(动态规划)

    Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the ...

  2. 【leetcode】 Interleaving String (hard)

    Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2. For example,Given:s1 = ...

  3. hiho一下第91周《Events Arrangement》(前半部分)

    题目大意 现在有一场持续时间为M的游乐会,在游乐会上有N种不同的表演节目,同一时间只能有一个节目进行表演. 每种节目最多可以表演K次,且每种节目具有自己的三个属性值a[i],b[i],c[i]. 当一 ...

  4. 一个人ACM(我们赶上了ACM)

    时间过得真快,不经意间我已经花了两年的大学生活,现在是时候写的东西.纪念馆两年左右的时间,最近一直在玩博客.我写了一个博客.纪念我们终将逝去的青春. 就从报考说起吧.高考成绩一般,自己选择了土建类的学 ...

  5. HDU 2064 菜鸡第一次写博客

    果然集训就是学长学姐天天传授水铜的动态规划和搜索,今天讲DP由于困意加上面瘫学长"听不懂就是你不行"的呵呵传授,全程梦游.最后面对连入门都算不上的几道动态规划,我的内心一片宁静,甚 ...

  6. 《剑指offer》矩形覆盖

    一.题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形.请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? 二.输入描述 输入n 三.输出描述 输出有多少种不同的覆 ...

  7. 【u025】贝茜的晨练计划

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 奶牛们打算通过锻炼来培养自己的运动细胞,作为其中的一员,贝茜选择的运动方式是每天进行N(1 <= ...

  8. 面试官:你有m个鸡蛋,如何用最少的次数测出鸡蛋会在哪一层碎?

    假设你面前有一栋n层的大楼和m个鸡蛋,假设将鸡蛋从f层或更高的地方放扔下去,鸡蛋才会碎,否则就不会.你需要设计一种策略来确定f的值,求最坏情况下扔鸡蛋次数的最小值. leetcode原题链接 乍一看这 ...

  9. 洛谷P1002过河卒java100分题解

    题目描述如图: 这道题我以前以回溯的方法做,只能拿到60分 现在才发现是道动态规划题 解题思路: 创建一个(0,0)到终点打小的二维数组表示棋盘 每个坐标的值为此位置到终点的路数 最下方一排和最右方一 ...

随机推荐

  1. 〖Linux〗build ssh for Arm

    1. 交叉编译环境: export ARCH=arm export SUBARCH=arm export PATH=/opt/FriendlyARM/toolschain//bin:$PATH exp ...

  2. 混合用法模式 __name__和__main__

    # -*- coding: utf-8 -*- #python 27 #xiaodeng #混合用法模式 __name__和__main__ #可把文件作为模块导入,并以独立式程序的形式运行,每个模块 ...

  3. java中的 public protected friendly private

    1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可以直 ...

  4. iOS利用SDWebImage实现缓存的计算与清理

    概述 可以仅仅清理图片缓存, 也可以清理所有的缓存文件(包括图片.视频.音频等). 详细 代码下载:http://www.demodashi.com/demo/10717.html 一般我们项目中的缓 ...

  5. iOS-夜间模式(换肤设置)

    概述 iOS 开发中有时候会有夜间模式(换肤设置)的需求, 主要是更改相关颜色操作每次切换夜间/白天模式时,都会发出通知给所有ViewController,让它们切换到相应的主题. 详细 代码下载:h ...

  6. springmvc访问静态资源的springmvc.xml配置

    一. 问题及需求 由于Spring MVC的web.xml文件中关于DispatcherServlet拦截url的配置为"/",拦截了所有的请求,同时*.js,*.jpg等静态资源 ...

  7. mysql 必须掌握的工具pt-query-digest安装

    mysql 必须掌握的工具pt-query-digest 古人云:工欲善其事,必先利其器.作为一名优秀的mysql dba也需要有掌握几个好用的mysql管理工具,所以我也一直在整理和查找一些能够便于 ...

  8. 【jQuery】页面顶部显示的进度条效果

    <!Doctype html> <html> <head> <title>页面顶部显示的进度条效果</title> <meta htt ...

  9. Accounting_会计电算化工作指南

    会计电算化工作指南 会计电算化实施的内容目标及原则 企业会计电算化的实施,也就是企业建立会计电算化的整个过程,是一项复杂的系统工程.在整个系统的实施过程中,包括会计电算化工作的规划,会计信息的建立与管 ...

  10. SYS_数据访问权限Operation Unit和Ledger的访问设定(案例)

    2014-06-01 Created By BaoXinjian