20200411(动态规划)

1、最大跳跃( jump.cpp ) hdu 1087

这个题目其实就是一个最长不下降子序列的题目,但是不同的是需要知道最大的序列和,比较基础

1、最大跳跃( jump.cpp ) hdu 1087
【问题描述】
最近有一个跳跃游戏十分受欢迎。
这个游戏可以由两个或两个以上的玩家玩。它由一个棋盘和一些棋子组成,所有棋子都用正整数或“start”或“end”标记。玩家从起点开始,最后必须跳到终点。在跳跃的过程中,玩家将访问路径中的棋子,但是每个人都必须从一个棋子跳到另一个绝对更大的棋子(你可以假设起点是最小值,终点是最大值) 。所有玩家都不能后退,一次跳跃可以从一个棋子跳到下一个,也可以跨越多个棋子,甚至你可以直接从起点跳到终点(在这种情况下,你当然会得零分)。如果只有一个玩家能够根据他的跳跃解决方案获得更高的分数时,他才是赢家。请注意,您的分数来自您跳跃路径中棋子的总价值。你的任务是根据给定的棋子列表输出最大值。
【输入说明】
输入包含多个测试用例。每一个测试用例都被描述成如下一行:
n value1 value2 ……valuen
保证n不超过1000,并且所有的值I都在32-int的范围内。从0开始的测试用例终止输入,并且这个测试用例不被处理。
【输出说明】
对于每种情况,根据规则打印最大值,一行一种情况。
【输入样例1】
3 1 3 2
4 1 2 3 4
4 3 3 2 1
0
【输出样例1】
4
10
3
最大跳跃
#include <bits/stdc++.h>
using namespace std;
const int N=1005,inf=0x3f3f3f;
int n,a[N],f[N],ans;
int main()
{
    
    while(cin>>n&&n){
        memset(f,0,sizeof(f));
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;i++){
            cin>>a[i];f[i]=a[i];
        }
        ans=f[1];
        for(int i=2;i<=n;i++)
        {
            for(int j=1;j<i;j++)
                if(a[j]<a[i])
                    f[i]=max(f[i],f[j]+a[i]);
            ans=max(ans,f[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

2、龟兔赛跑

这个题目就是一个动态规划,就是自己去定义一个状态,d[i]表示到第i个站点充电时最少花费的时间,一些小的限制条件应该是比较好想到的,注意要用double 类型来进行比较

2、 龟兔赛跑 hdu 2059
【问题描述】
据说在很久很久以前,可怜的兔子经历了人生中最大的打击——赛跑输给乌龟后,心中郁闷,发誓要报仇雪恨,于是卧薪尝胆潜心修炼,终于练成了绝技,能够毫不休息得以恒定的速度(VR m/s)一直跑。兔子一直想找机会好好教训一下乌龟,以雪前耻。兔子向乌龟发起挑战。虽然乌龟深知获胜希望不大,不过迫于舆论压力,只能接受挑战。
比赛是设在一条笔直的道路上,长度为L米,规则很简单,谁先到达终点谁就算获胜。无奈乌龟自从上次获胜以后,成了名龟,被一些八卦杂志称为“动物界的刘翔”,广告不断,手头也有了不少积蓄。为了能够再赢兔子,乌龟不惜花下血本买了最先进的武器——“"小飞鸽"牌电动车。这辆车在有电的情况下能够以VT1 m/s的速度“飞驰”,可惜电池容量有限,每次充满电最多只能行驶C米的距离,以后就只能用脚来蹬了,乌龟用脚蹬时的速度为VT2 m/s。更过分的是,乌龟竟然在跑道上修建了很多很多(N个)的供电站,供自己给电动车充电。其中,每次充电需要花费T秒钟的时间。当然,乌龟经过一个充电站的时候可以选择去或不去充电。
比赛马上开始了,兔子和带着充满电的电动车的乌龟并列站在起跑线上。你的任务就是写个程序,判断乌龟用最佳的方案进军时,能不能赢了一直以恒定速度奔跑的兔子。
【输入说明】
本题目包含多组测试,请处理到文件结束。每个测试包括四行:
第一行是一个整数L代表跑道的总长度
第二行包含三个整数N,C,T,分别表示充电站的个数,电动车冲满电以后能行驶的距离以及每次充电所需要的时间
第三行也是三个整数VR,VT1,VT2,分别表示兔子跑步的速度,乌龟开电动车的速度,乌龟脚蹬电动车的速度
第四行包含了N(N<=100)个整数p1,p2...pn,分别表示各个充电站离跑道起点的距离,其中0<p1<p2<...<pn<L
其中每个数都在32位整型范围之内。
【输出样例】
当乌龟有可能赢的时候输出一行 “What a pity rabbit!"。否则输出一行"Good job,rabbit!";
题目数据保证不会出现乌龟和兔子同时到达的情况。
【输入样例】
100
3 20 5
5 8 2
10 40 60
100
3 60 5
5 8 2
10 40 60
【输出样例】
Good job,rabbit!
What a pity rabbit!
龟兔赛跑
#include <bits/stdc++.h>
using namespace std;
const int N=105,inf=0x3f3f3f;
int l,n,c,t,rv,tv1,tv2,a[N];
double f[N],len,rt,tt;
int main()
{
    while(cin>>l){
        scanf("%d %d %d",&n,&c,&t);
        scanf("%d %d %d",&rv,&tv1,&tv2);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        a[n+1]=l;
        rt=l*1.0/rv;//兔子需要花的时间
        tt=0;
        for(int i=1;i<=n+1;i++){
            f[i]=inf;
            for(int j=0;j<i;j++){
                len=a[i]-a[j];
                double tmp;
                if(c>=len){
                    tmp=f[j]+len*1.0/tv1;
                }
                else {
                    tmp=f[j]+(len-c)*1.0/tv2+c*1.0/tv1;
                }
                if(j)//如果不是刚出发,代表在j充了一次电
                    tmp+=t;
                f[i]=min(f[i],tmp); 
            }
        }
        tt=f[n+1];
        if(rt<tt) printf("Good job,rabbit!\n");
        else printf("What a pity rabbit!\n");
    }
    return 0;
}

 3、拒绝病毒(virus.cpp)

很难,kmp算法与最长公共子序列的结合:kmp算法都还没搞太清楚,代码先放这里

【问题描述】
通过删除一个字符串中的某些元素而不改变其余元素的顺序,可以派生出该字符
串的一个子序列。例如,序列 BDF 是 ABCDEF 的子序列。字符串的子字符串是该字符串的连续子序列。例如,BCD 是 ABCDEF 的子串。你得到了两个字符串 s1,s2 和另一个名为 virus 的字符串。你的任务是找到 s1和 s2 的最长公共子序列,同时不包含 virus 子字符串。
【输入说明】
输入三行,每行一个字符串:s1、s2 和 virus(1 ≤ | s1 |、 | s2 |、 |virus| ≤ 100)。每个字符串仅由大写英文字母组成。
【输出说明】
输出不带病毒的 s1 和 s2 的最长公共子序列。如果有多个答案,任何一个都将被
接受。如果没有有效的公共子序列,则输出 0。
【输入样例 1】
KEAJKEQSLOBSROFGZ
ZOVGURWZLWVLUXTH
OZ
【输出样例 1】
ORZ
【输入样例 2】
DD
DDD
D
【输出样例 20
拒绝病毒(virus.cpp)
#include <bits/stdc++.h>
using namespace std;
string a,b,c;
int t[105],dp[105][105][105],sa,sb,sc;

void kmp(){
    int i=0,j=-1;
    t[0]=-1;
    for(i=1;i<sc;i++){
        while(j>=0&&c[i-1]!=c[j])j=t[j];
        j++;
        t[i]=j;
    }
}

int cek(int p,int r){
    while(r>=0&&a[p]!=c[r])r=t[r];
    return r;
}

int lcs(int p,int q,int r){
    if(r==sc)return -1000;
    if(p==sa||q==sb)return 0;
    if(dp[p][q][r]!=-1)return dp[p][q][r];
    dp[p][q][r]=max(lcs(p+1,q,r),lcs(p,q+1,r));
    if(a[p]==b[q])dp[p][q][r]=max(dp[p][q][r],1+lcs(p+1,q+1,cek(p,r)+1));
    return dp[p][q][r];
}

int main(){
    freopen("virus.in","r",stdin);
    freopen("virus.out","w",stdout);
    cin>>a>>b>>c;
    sa=a.size();
    sb=b.size();
    sc=c.size();
    kmp();
    memset(dp,-1,sizeof(dp));
    int ans=lcs(0,0,0);
    if(ans==0)return cout<<"0",0;
    int p=0,q=0,r=0;
    while(ans>0){
        int gg=cek(p,r)+1;
        int t1=lcs(p+1,q,r),t2=lcs(p,q+1,r),t3=(a[p]==b[q]?1+lcs(p+1,q+1,gg):-1000);
        if(t1>=t2&&t1>=t3)p++;
        else{
            if(t2>=t1&&t2>=t3)q++;
            else{cout<<a[p++];q++;r=gg;ans--;}
        }
    }    
}
View Code

4、神秘的礼物(gift.cpp)

相对于第三题就没有这么难了咳咳,其实就像是俄罗斯套娃一样,主要还是注意一下输出

【问题描述】
彼得的朋友要过生日了,彼得决定给他寄一张卡片表示祝贺。为了使他的礼物更
神秘,他决定做一个链子。这里的链是这样一个信封序列 a = {a1,a2,…,an},
其中第 i 个信封的宽度和高度分别严格高于第(i - 1)个信封的宽度和高度。
链大小是链中信封的数目。
彼得想把他的信封做成最大尺寸的链子。如果卡片的宽度和高度分别低于链中最
小信封的宽度和高度,则卡片能够被装入链中(禁止转动卡片和信封)。
彼得有很多信封和很少的时间,这项艰巨的任务就交给你了。
【输入说明】
第一行包含整数 n,w,h(1 ≤ n ≤ 50001 ≤ w, h ≤ 10^6),表示彼得拥有的
信封数量、卡片宽度和高度。接下来是 n 行,每行包含两个整数 wi 和 hi,分别
表示第 i 个信封的宽和高(1 ≤ wi,hi ≤ 10^6)。
【输出说明】
第一行输出最大链大小。
第二行输出满足要求的信封的编号链(用空格隔开),从最小信封的编号开始输
出。请记住,卡片应该放在最小的信封里。
如果最大大小的链不是唯一的,请输出其中任何一个链即可。
如果卡不适合任何信封,请输出 0。
【输入样例 12 1 1
2 2
2 2
【输出样例 11
1
【输入样例 23 3 3
5 4
12 11
9 8
【输出样例 23
1 3 2
神秘的礼物
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 5005
using namespace std;
int w[N],h[N],dp[N],ans[N],n;
int f(int v){
    if(dp[v]!= 0) return dp[v];
    int Max =0,k;
    for(int i =1; i <= n; i++)
        if(w[v] < w[i] && h[v] < h[i]){
            k = f(i);
            if(k > Max){
                Max = k;
                ans[v] = i;
            }
        }
    return dp[v] = Max+1;
}
int main(){
    freopen("gift.in","r",stdin);
    freopen("gift.out","w",stdout);
    scanf("%d",&n);
    for(int i = 0; i <= n; i++)
        scanf("%d%d",&w[i],&h[i]);
    f(0);
    cout << dp[0]-1<<endl;
    for(int i = 0; ans[i]; i = ans[i])
        cout<<ans[i]<<" ";
    return 0;
}

 

posted @ 2020-04-14 10:18  sumoier  阅读(191)  评论(0)    收藏  举报