09-03 HDU_Steps3.2 简单DP HDU1003 HDU1159 HDU1087 HDU1160 HDU1058 HDU2084 HDU1176 HDU2571

来源:互联网 发布:sql server check约束 编辑:程序博客网 时间:2024/05/21 19:44

HDU STEPS3.2 主要都是DP的入门题,最长XX序列,以及数塔问题


3.2.1 HDU1003 Max Sum 求连续区间使和最大

首先将数列转化成前N项和的数列,这样[a,b]区间的和可以表示为sum[b]-sum[a-1]

之后只要扫描一次数组,记录该位置之前的最小sum[]值,如果当前值减去该最小值得到的结果大于目前保存的最大值,则跟新最大值.

#include <cstdio>using namespace std;int a[100005];int main(){int cas,n;scanf("%d",&cas);for(int ca=1;ca<=cas;ca++){scanf("%d",&n);a[0]=0;for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i]+=a[i-1];} //标记最小值,如果当前值减最小值小于结果,更新结果 int ind=0,st=0,en=1,v=a[1];for(int i=2;i<=n;i++){if(a[i-1]<a[ind])ind=i-1;if(a[i]-a[ind]>v){st=ind,en=i,v=a[i]-a[ind];}}printf("Case %d:\n",ca);printf("%d %d %d\n",v,st+1,en);if(ca!=cas)printf("\n");}return 0;} 

3.2.2 HDU1159 Common Subsequence 

最长公共子序列,不能再裸了..


3.2.3 HDU1087 Super Jumping!

裸的最长上升子序列,只是每次加分值,而不是+1;

#include <cstdio>using namespace std;int n,d[1050],a[1050];int dp(){int rs=0;for(int i=1;i<=n;i++){d[i]=a[i];for(int j=1;j<i;j++){if(a[i]>a[j]&&a[i]+d[j]>d[i])d[i]=a[i]+d[j];}if(d[i]>rs)rs=d[i];}return rs;}int main(){while(scanf("%d",&n),n){for(int i=1;i<=n;i++)scanf("%d",&a[i]);printf("%d\n",dp());}return 0;}


3.2.4 HDU1160 FatMouse`s Speed 最长序列的一个变形,DP时加了一个限制条件

按w升序,s降序排列后进行DP找最长序列,用pre[]数组记录该点的前驱,从而打印路径

#include <cstdio>#include <algorithm>using namespace std;struct mouse{int w,s,id;bool operator < (const mouse& m) const{return w<m.w||w==m.w&&s>m.s;}}m[1005];int d[1005],pre[1005],ms=1,ans[1005];void solve(){/*最长XX序列变形 w升序,s降序 在原DP上加一个限制条件即可 DP it*/d[0]=-1;int ind=0;for(int i=1;i<=ms;i++){int t=0;for(int j=1;j<i;j++){if(m[i].w>m[j].w&&m[i].s<m[j].s&&d[j]+1>d[t]+1){t=j;}}if(t==0)d[i]=1,pre[i]=-1;else{d[i]=d[t]+1;pre[i]=t;}if(d[i]>d[ind])ind=i; }//out answer int as=0;while(ind!=-1){ans[as++]=m[ind].id;ind=pre[ind];}printf("%d\n",as);for(int i=as-1;i>=0;i--)printf("%d\n",ans[i]);}int main(){while(scanf("%d%d",&m[ms].w,&m[ms].s)!=EOF)m[ms].id=ms,ms++;sort(m+1,m+ms+1);solve();//system("pause");return 0;}

3.2.5 HDU1058 Humble Numbers

每一个新的数都可以用{2,3,5,7}中的一个乘以已得到序列中的某个数得到,所以F(N)=min{f(a)*2,f(b)*3,f(c)*5,f(d)*7},F(N)>F(N-1),其中a,b,c,d是刚刚使{2,3,5,7}与该项积大于F(N-1)的数,即2*F(a-1)<F(N-1)<2*F(a),注意对当前a,b,c,d的保存..这题的输出也比较阴险..

#include <cstdio>#include <algorithm>#include <cstdlib>using namespace std;int a[6000],n;int min4(int a,int b,int c,int d){return min(min(a,b),min(c,d));}void init(){/*用2,3,5,7乘已得到数列中的数,当该数不大于a[i-1]时,标记++,直到大于a[i-1]为止最后选去4个数中较小的一个 */ a[1]=1;int s[4]={2,3,5,7}; int st[4]={0,0,0,0};//标记乘到a[]中的哪一个数了 for(int i=2;i<=5842;i++){ for(int j=0;j<4;j++)while(s[j]*a[st[j]]<=a[i-1])st[j]++; a[i]=min4(s[0]*a[st[0]],s[1]*a[st[1]],s[2]*a[st[2]],s[3]*a[st[3]]);}}int main(){init();char c[3];while(scanf("%d",&n),n){//阴险的输入输出 if(n%100!=11&&n%10==1)strcpy(c,"st"); else if(n%100!=12&&n%10==2)strcpy(c,"nd"); else if(n%100!=13&&n%10==3)strcpy(c,"rd"); else strcpy(c,"th");printf("The %d%s humble number is %d.\n",n,c,a[n]);}return 0;}

3.2.6 HDU2084 数塔 DP入门经典题,自下向上计算


3.2.7 HDU1176 免费馅饼 其实就是数塔的一个变形,这题过了数塔就算理解了,在能接到馅饼的时间先填上馅饼数,其它位置为0,然后自终态向前DP,

#include <cstdio>#include <string.h>#include <algorithm> using namespace std;int d[100005][11];int n,mat,a,b;int main(){while(scanf("%d",&n),n){mat=0;memset(d,0,sizeof d);while(n--){scanf("%d%d",&a,&b);if(b>mat)mat=b;d[b][a]++;}//数塔的变形 for(int t=mat-1;t>=0;t--){d[t][0]+=max(d[t+1][0],d[t+1][1]);d[t][10]+=max(d[t+1][10],d[t+1][9]);for(int j=1;j<=9;j++)d[t][j]+=max(d[t+1][j-1],max(d[t+1][j],d[t+1][j+1]));}printf("%d\n",d[0][5]);}return 0;}


3.2.8 HDU2571 命运

其实依然是数塔的变形,自魔王向前考虑

#include <cstdio>#include <algorithm>#include <cmath>using namespace std;int cas,n,m;int a[25][1005];int main(){scanf("%d",&cas);while(cas--){memset(a,0,sizeof a);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]);//DP for(int i=n-1;i>=1;i--)a[i][m]+=a[i+1][m];for(int i=m-1;i>=1;i--){int r=a[n][i+1];for(int j=i*2;j<=m;j+=i)r=max(r,a[n][j]);a[n][i]+=r;}for(int i=n-1;i>=1;i--){for(int j=m-1;j>=1;j--){int r=max(a[i+1][j],a[i][j+1]);for(int k=j*2;k<=m;k+=j)r=max(r,a[i][k]);a[i][j]+=r;}}printf("%d\n",a[1][1]);}return 0;} 


原创粉丝点击