kuangbin专题:基础DP(部分题的思路)

1.Max Sum Plus Plus

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

题意:给出n个整数a1,a2,… ,an及正整数m,求最大m个不相交子段和。

解题思路:用dp[i][j]表示从前j个数中恰好选出i组数的最大和 ,就有dp[j][j]=max(dp[i][j−1]+a[j],max(dp[i−1][i-1~j-1])+a[j])。可以看到每一层的dp仅与上一层有关系,所以可以建立一个数组存上一层的最大值,就可以用一维的dp解决问题。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
int dp[1000005],mmax[1000005],a[1000005];
int main(){
	int m,n;
	while(cin>>m>>n){
		memset(dp,0,sizeof(dp));
		memset(mmax,0,sizeof(mmax));
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		int mm;
		for(int i=1;i<=m;i++){
			mm=-INF;
			for(int j=i;j<=n;j++){
				dp[j]=max(dp[j-1]+a[j],mmax[j-1]+a[j]);
				mmax[j-1]=mm;
				mm=max(mm,dp[j]);
			}
		}
		cout<<mm<<"\n";
	}
	return 0;	
}

2.Ignatius and the Princess IV

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

题意:给出奇数n和n个整数,找出其中出现次数≥(n+1)/2的数。

解题思路:貌似开了个桶救过了???

#include<iostream>
#define ll long long
using namespace std;
int t[100005];
int main(){
	int n;
	while(cin>>n){
		int wow;
		for(int i=0;i<n;i++){
			int a;scanf("%d",&a);
			t[a]++;
			if(t[a]>=(n+1)/2)wow=a;
		}
		cout<<wow<<"\n";
	}
	return 0;
}

3.Monkey and Banana

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

题意:给出n种方块(每种方块的数目无限),给出每种方块的长宽高,当底面的两个尺寸分别都严格小于另一个方块的两个尺寸,可以将其叠上去,求用这些方块能叠的最高高度。(注意:方块可以按需求重新定义地面)

解题思路:我觉得是最长上升子序列的变种,用结构体储存方块类型(这里我是一种拆成三种算,显然底面相同的方块只能使用一次,排序完之后直接简单dp)。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fo(i,n) for(int i=0;i<n;i++)
struct hhh{
	ll x,y,z;
};
bool cmp(hhh a,hhh b){
	if(a.x==b.x)return a.y>b.y;
	else return a.x>b.x;
}
int main()
{  
	int qi=0;int n;
	while(cin>>n){
		if(n==0)return 0;
		hhh h[1005];
		int s=0;qi++;
		fo(i,n){
			int x,y,z;
			cin>>x>>y>>z;
			hhh t;
			t.z=z;t.x=x;t.y=y;if(t.y>t.x)swap(t.y,t.x);h[s++]=t;
			t.z=x;t.x=z;t.y=y;if(t.y>t.x)swap(t.y,t.x);h[s++]=t;
			t.z=y;t.x=x;t.y=z;if(t.y>t.x)swap(t.y,t.x);h[s++]=t;
		}
		sort(h,h+s,cmp);
		ll dp[1005];
		fo(i,s)dp[i]=h[i].z;
		for(int i=0;i<s;i++)
			for(int j=0;j<i;j++)
				if(h[j].x>h[i].x&&h[j].y>h[i].y)
					dp[i]=max(dp[i],dp[j]+h[i].z);
		ll m=0;fo(i,s)m=max(m,dp[i]);
		printf("Case %d: maximum height = ",qi);
		cout<<m<<"\n";
	}
}

4.Super Jumping! Jumping! Jumping!

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

题意&解题思路:最大上升子序列和。直接贴代码吧。

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,a[1001],dp[1001];
	while(cin>>n){
		if(n==0)return 0;
		for(int i=0;i<n;i++){
			cin>>a[i];
			dp[i]=a[i];
		}
		for(int i=0;i<n;i++){
			for(int j=0;j<i;j++){
				if(a[j]<a[i])dp[i]=max(dp[i],dp[j]+a[i]);
			}
		}
		sort(dp,dp+n);
		cout<<dp[n-1]<<"\n";
	}	
}

5.Piggy-Bank

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

题意&解题思路:完全背包问题。

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
	int q;cin>>q;
	while(q--){
		int m1,m2;
		cin>>m1>>m2;
		int m=m2-m1,n;
		cin>>n;
		int f[10005],w[1005],v[1005];
		for(int i=0;i<n;i++)scanf("%d%d",&w[i],&v[i]);
		for(int i=1;i<=m;i++)f[i]=100000007;
		f[0]=0;
		for(int i=0;i<n;i++){
			for(int j=v[i];j<=m;j++){
				f[j]=min(f[j],f[j-v[i]]+w[i]);
			}
		}
		if(f[m]==100000007)cout<<"This is impossible.\n";
		else cout<<"The minimum amount of money in the piggy-bank is "<<f[m]<<".\n";
	} 
	return 0;	
}

6.Tickets

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

题意:卖电影票的joe希望能早点回家,他可以单独卖给一个人或者同时卖给相邻的两个人,你是上帝知道卖给每个人和每相邻两个人的时间,会DP的你能帮帮他吗?

解题思路:设dp[i]为买票给前i个人花费的最小时间,a[i]为第i个人单独买票花费的时间,b[i]为第i个人和他前一个人一起买票所花费的时间,则有状态转移方程:dp[i]=min(dp[i-1]+a[i],dp[i-2]+b[i])。(注意12小时制和输出前导零)

#include<bits/stdc++.h>
#define ll long long
#define intq() int Qq;cin>>Qq;while(Qq--)
using namespace std;
int main()
{
	intq(){
		int a[3000],b[3000],dp[3000],n;
		cin>>n;
		for(int i=0;i<n;i++)cin>>a[i];
		for(int i=1;i<n;i++)cin>>b[i];
		dp[0]=a[0];
		dp[1]=min(a[0]+a[1],b[1]);
		for(int i=2;i<n;i++)
			dp[i]=min(dp[i-1]+a[i],dp[i-2]+b[i]);
		int h=8,Min=0,s=dp[n-1];
		Min+=(s/60);s%=60;
		h+=(Min/60);Min%=60;
		bool am=0;
		if((h/12)%2==0)am=1;
		h%=12;
		if(am)printf("%02d:%02d:%02d am\n",h,Min,s);
		else printf("%02d:%02d:%02d pm\n",h,Min,s);
	}
	return 0;
 } 

7.最少拦截系统

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

题意:有n发导弹按顺序来袭,现有一种拦截系统能拦截导弹,但拦截的每一发炮弹都不能超过前一发的高度,求最少需要几套拦截系统。

解题思路:其实就是最长上升子序列。

#include<iostream>
using namespace std;
int main()
{
	int n;
	int a[10005];
	int dp[10005];
	while(cin>>n){
		for(int i=0;i<n;i++)
	{
		cin>>a[i];
		dp[i]=1;
	}
	int maxx=0;
	for(int i=0;i<n;i++)
	{
		for(int j=i-1;j>=0;j--)
		{
			if(a[j]<a[i])
			{
				dp[i]=max(dp[i],dp[j]+1);
			}
			maxx=max(maxx,dp[i]);
		}
	}
	cout<<maxx<<"\n";
	}
	return  0;
}

另附上一种神奇的做法:

#include<iostream>
#include<set>
using namespace std;
int main(){
	int n,p;
	while(cin>>n){
		set<int>a;
		for(int i=0;i<n;i++){
			cin>>p;
			if(a.find(p)==a.end()&&a.upper_bound(p)!=a.end()){
				a.erase(a.upper_bound(p));
			}
            a.insert(p);
		}
		cout<<a.size()<<"\n";
	}	
}

8.Longest Ordered Subsequence

链接:http://poj.org/problem?id=2533

题意&解题思路:还是最长上升子序列。

#include<iostream>
#define ll long long
using namespace std;
int dp[1005];
int a[1005]; 
int main(){
	int n;cin>>n;
	for(int i=0;i<n;i++){
		cin>>a[i];
		dp[i]=1;
	}
	for(int i=0;i<n;i++){
		for(int j=0;j<i;j++){
			if(a[i]>a[j])dp[i]=max(dp[i],dp[j]+1);
		}
	}
	int m=0;
	for(int i=0;i<n;i++){
		if(dp[i]>m)m=dp[i];
	}
	cout<<m;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值