09-03 HDU_Steps3.2 簡單DP HDU1003 HDU1159 HDU1087 HDU1160 HDU1058 HDU2084 HDU1176 HDU2571

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;	
} 


發佈了91 篇原創文章 · 獲贊 6 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章