4.28考试总结(上午)

1、挖地雷(lei.cpp)时空限制1000ms / 128MB

题目描述

在一个地图上有NN个地窖(N≤20),每个地窖中埋有一定数量的地雷。同时,给出地窖之间的连接路径。当地窖及其连接的数据给出之后,某人可以从任一处开始挖地雷,然后可以沿着指出的连接往下挖(仅能选择一条路径),当无连接时挖地雷工作结束。设计一个挖地雷的方案,使某人能挖到最多的地雷。

输入格式:(lei.in)

有若干行。

第1行只有一个数字,表示地窖的个数N。

第2行有N个数,分别表示每个地窖中的地雷个数。

第3行至第N+1行表示地窖之间的连接情况:

第3行有n-1个数(0或1),表示第一个地窖至第2个、第3个、…、第n个地窖有否路径连接。如第3行为11000…0,则表示第1个地窖至第2个地窖有路径,至第3个地窖有路径,至第4个地窖、第5个、…、第n个地窖没有路径。

第4行有n-2个数,表示第二个地窖至第3个、第4个、…、第n个地窖有否路径连接。

… …

第n+1行有1个数,表示第n-1个地窖至第n个地窖有否路径连接。(为0表示没有路径,为1表示有路径)。

输出格式:(lei.out)

有两行

第一行表示挖得最多地雷时的挖地雷的顺序,各地窖序号间以一个空格分隔,不得有多余的空格。

第二行只有一个数,表示能挖到的最多地雷数。

输入输出样例

输入样例#1:

5

10 8 4 7 6

1 1 1 0

0 0 0

1 1

1

输出样例#1: 

1 3 4 5

27

【思路】:

就是直接用dp,用f[i]表示从i挖能挖到的最多的地雷,f[i]=max(f[i],f[j])

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int n,pre[215],a[215],g[215][215],ans,t,f[215];
void print(int x) {//递归输出路径
    if(pre[x]==0) {
        printf("%d",x);
        return ;
    }
    print(pre[x]);
    printf(" %d",x);//注意空格问题 
}

int main() {
    freopen("lei.in","r",stdin);
    freopen("lei.out","w",stdout);
    n=read();
    for(int i=1; i<=n; ++i) {//读入地雷
        scanf("%d",a+i);
    }
    for(int i=1; i<=n; ++i) {
        for(int j=i+1; j<=n; ++j) {
            int x=read();
            if(x==1)
                g[i][j]=1;//存是否存在路径
        }
    }
    for(int i=1; i<=n; ++i) {
        for(int j=1; j<=n; ++j) {
            if((g[j][i]==1)&&(f[j]>f[i])) {
                f[i]=f[j];
                pre[i]=j;
            }
        }
        f[i]+=a[i];
        if (f[i]>ans) {
            ans=f[i];
            t=i;
        }
    }
    print(t);
    cout<<'\n';
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

题目背景

一年一度的“跳石头”比赛又要开始了!

题目描述

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。

输入输出格式

第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L≥1 且 N≥M≥0。

接下来 N 行,每行一个整数,第 i 行的整数Di​(0<Di​<L), 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输入输出样例

输入样例#1:
25 5 2 
2
11
14
17 
21
输出样例#1: 
4

说明

输入输出样例 1 说明:将与起点距离为 2和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。

另:对于 20%的数据,0 ≤ M ≤ N ≤ 10。

对于50%的数据,0 ≤ M ≤ N ≤ 100。

对于 100%的数据,0 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,000。

【思路】:

用二分答案来求。

至于为什么用二分答案?学长说过只要出现上面加粗的字就用,嘿嘿

为什么能用二分答案?

很简单注意输入距离从近到远,答案有单调性

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int a[2000002],mid,l,r,ans,L,N,M,now_juli,js;
int check(int x) {
     now_juli=0,js=0;
    /*js是表示搬走的石头数量,now_juli是当前的石头离起点的距离*/
    for(int i=1; i<=N+1; ++i) {
        if(a[i]-now_juli<x) { //比较两点之间的距离
            js++;
        } else {
            now_juli=a[i];
        }
    }
    if(js>M) 
        return 0;
}
int main() {
//    freopen("stone.in","r",stdin);
//    freopen("stone.out","w",stdout);
    scanf("%d%d%d",&L,&N,&M);
    if(N==0&&M==0)
    {
        cout<<L;
        return 0;
    }
    int l=0,r=L;//初始化二分边界
    for(int i=1; i<=N; i++)
        scanf("%d",&a[i]);
    /*注意输入距离从近到远,答案有单调性*/
    a[N+1]=L;//注意设置终点,呜呜呜浪费我20分钟查错误 
    while(l<=r) {
        mid=(l+r)/2;
        if(check(mid)) { //
            l=mid+1;
            ans=mid;
        } else {     //
            r=mid-1;
        }
    }
    cout<<ans;
    fclose(stdin);
    fclose(stdout);
    return 0;
}

3、花匠flower.cpp(时空限制1000ms / 128MB)

题目描述

花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。

具体而言,栋栋的花的高度可以看成一列整数h1​,h2​,...,hn​。设当一部分花被移走后,剩下的花的高度依次为g1​,g2​,...,gm​,则栋栋希望下面两个条件中至少有一个满足:

条件 A:对于所有g2i​>g2i−1​,g2i​>g2i+1​

条件 BB:对于所有g2i​<g2i−1​,g2i​<g2i+1​

注意上面两个条件在m=1时同时满足,当m > 1时最多有一个能满足。

请问,栋栋最多能将多少株花留在原地。

输入输出格式

输入格式:

第一行包含一个整数n,表示开始时花的株数。

第二行包含n个整数,依次为h1​,h2​,...,hn​,表示每株花的高度。

输出格式:

一个整数m,表示最多能留在原地的花的株数。

输入输出样例

输入样例flower.in

5

5 3 2 1 2

输出样例flower.out

3

说明

【输入输出样例说明】

有多种方法可以正好保留 3 株花,例如,留下第 1、4、5 株,高度分别为 5、1、2,满足条件 B。

【数据范围】

对于 20%的数据,n ≤ 10;

对于30%的数据,n ≤ 25;

对于 70%的数据n≤1000,0≤hi​≤1000;

对于100%的数据,1≤n≤100,000,0≤hi​≤1,000,000,所有的hi​随机生成,所有随机数服从某区间内的均匀分布。

 【思路】:和合唱队形一样的思路。用二维数组表示到i点的最长上升和最长下降.

然后统计波峰和波谷

猜你喜欢

转载自www.cnblogs.com/pyyyyyy/p/10783212.html