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