题解-百度2017春招笔试真题编程题集合

题目链接:https://www.nowcoder.com/test/4998655/summary

一共五题,从第五题开始写,难度由难到易

------------------------------------------------------------------------------------------------

第五题

度度熊最近对全排列特别感兴趣,对于1到n的一个排列,度度熊发现可以在中间根据大小关系插入合适的大于和小于符号(即 '>' 和 '<' )使其成为一个合法的不等式数列。但是现在度度熊手中只有k个小于符号即('<'')和n-k-1个大于符号(即'>'),度度熊想知道对于1至n任意的排列中有多少个排列可以使用这些符号使其为合法的不等式数列。

输入描述:
输入包括一行,包含两个整数n和k(k < n ≤ 1000)
输出描述:
输出满足条件的排列数,答案对2017取模。
示例1
输入
5 2
输出
66
分析:

    多可能性/多状态情况,考虑动态规划,用前一状态递推出下一状态。用 dp[i][j] 表示 i 个数字 j 个小于号时的序列个数。

    1、序列至少两个数字,一个符号。即 1<2 或 2>1 。 此时 dp[2][0]=1, dp[2][1]=1 。

    2、i 个数字,j个符号时。

            此时新增的数为 i ,且一定是序列中最大的数,一共四种情况(以下用 i=4 举例)

            (1)从 dp[i-1][j-1] 在最右边添加一个小于号  ………<4,(4最大,序列一定成立)

                    共dp[i-1][j-1]种情况

            (2)从 dp[i-1][j-1] 中间任意一个>号左边添加一个<号  ……<4>……(4最大,对于左右两边都一定成立)

                    共dp[i-1][j-1]*(i-j)  种情况,(i-j 为>号的个数,i-j=(i-1)-(j-1)   )

            (3)从 dp[i-1][j] 在最左边添加一个 >号, 4>…………(4最大,序列一定成立)

                    共 dp[i-1][j] 种情况

            (4)从 dp[i-1][j] 中间任意一个<号右边添加一个>号(4最大,对于左右两边都一定成立)

                    共 dp[i-1][j]*j 种情况 (j 为 < 号的个数)

统计以上情况,得到以下递推式

dp[i][j]=dp[i-1][j-1]*(i-j)+dp[i-1][j]*(j+1)
完整代码
#include<cstdio>
#include<cstring>

int main(){
    int n,k;
    scanf("%d %d",&n,&k);
    int dp[n+1][n+1];
    memset(dp,0,sizeof(dp));
    dp[2][0]=1;    //初始化原始情况
    dp[2][1]=1;
    for(int i=3;i<=n;i++){
        for(int j=0;j<i;j++){
            if(j==0)dp[i][0]=1;
            else  dp[i][j]=(dp[i-1][j-1]*(i-j)+dp[i-1][j]*(j+1))%2017;     //递推
        }
    }
    printf("%d",dp[n][k]);
    return 0;
}

------------------------------------------------------------------------------------------------

第四题

度度熊有一个N个数的数组,他想将数组从小到大 排好序,但是萌萌的度度熊只会下面这个操作:
任取数组中的一个数然后将它放置在数组的最后一个位置。
问最少操作多少次可以使得数组从小到大有序?

输入描述:
首先输入一个正整数N,接下来的一行输入N个整数。(N <= 50, 每个数的绝对值小于等于1000)
输出描述:
输出一个整数表示最少的操作次数。
示例1
输入
4
19 7 8 25
输出
2
分析:

理解题意,就算用最笨的办法按从小到大的顺序抽出排到最后形成有序序列,最多也只有 n 次操作,每个数最多被操作一次。

那么只需要考虑哪些数可以不用被操作,即本来就和排完序后一致,即找到原数组中存在的排序数组中的最长前缀子序列

例如:

原数组:       19 7 8 25

排序数组:    7 8 19 25

原数组中 7, 8 两个数在原数组中就是有序前缀因此不用再排。需要执行的操作为剩下的数

再例如:

原数组:    6 1 5 2 3 4

排序数组: 1 2 3 4 5 6

原数组中 1 2 3 4 有序不用再调整,需要调整的即为剩下的数

完整代码
#include<cstring>
#include<stdio.h>
#include<algorithm>
using namespace std;
int ary[55],sort_ary[55];
int main()
{
    int n;
    scanf("%d",&n);
    int count=0;    //最长有序数组前缀子序列长度
    for(int i=0;i<n;++i)
    {
        scanf("%d",&ary[i]);
        sort_ary[i]=ary[i];
    }
    sort(sort_ary,sort_ary+n);
    for(int i=0;i<n;++i)
    {
        if(ary[i]==sort_ary[count])count++;    //统计
    }
    printf("%d",n-count);
    return 0;
}

------------------------------------------------------------------------------------------------

第三题

三维空间中有N个点,每个点可能是三种颜色的其中之一,三种颜色分别是红绿蓝,分别用'R', 'G', 'B'表示。
现在要找出三个点,并组成一个三角形,使得这个三角形的面积最大。
但是三角形必须满足:三个点的颜色要么全部相同,要么全部不同。

输入描述:
首先输入一个正整数N三维坐标系内的点的个数.(N <= 50) 

接下来N行,每一行输入 c x y z,c为'R', 'G', 'B' 的其中一个。x,y,z是该点的坐标。(坐标均是0到999之间的整数)
输出描述:
输出一个数表示最大的三角形面积,保留5位小数。
示例1
输入
5
R 0 0 0
R 0 4 0
R 0 0 3
G 92 14 7
G 12 16 8
输出
6.00000
分析:

每个点都有三维空间坐标,每三个点可以算出三条边长

使用海伦公式:p=(a+b+c)/2 ; S=sqrt(p*(p-a)*(p-b)*(p-c)); 得到面积

枚举同色情况和异色情况求出最大值

完整代码
#include<vector>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<stdio.h>
using namespace std;
struct pos    //用于记录点的位置信息
{
    double x;
    double y;
    double z;
};
 
double area(pos a,pos b,pos c)    //海伦公式求面积
{
    double lena=sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
    double lenb=sqrt((a.x-c.x)*(a.x-c.x)+(a.y-c.y)*(a.y-c.y)+(a.z-c.z)*(a.z-c.z));
    double lenc=sqrt((c.x-b.x)*(c.x-b.x)+(c.y-b.y)*(c.y-b.y)+(c.z-b.z)*(c.z-b.z));
    double s=(lena+lenb+lenc)/2;
    return sqrt(s*(s-lena)*(s-lenb)*(s-lenc));
}
 
int main()
{
    int n;
    pos temp;
    cin>>n;
    char color;
    vector<pos>r;
    vector<pos>g;
    vector<pos>b;
    while(n--)    //输入并按颜色分类
    {
        cin>>color>>temp.x>>temp.y>>temp.z;
        if(color=='R')r.push_back(temp);
        if(color=='G')g.push_back(temp);
        if(color=='B')b.push_back(temp);
    }
    double ans=0;
    for(int i=0;i<r.size();++i)
        for(int j=i+1;j<r.size();++j)
            for(int k=j+1;k<r.size();++k)
                ans=max(ans,area(r[i],r[j],r[k]));
 
    for(int i=0;i<g.size();++i)
        for(int j=i+1;j<g.size();++j)
            for(int k=j+1;k<g.size();++k)
                ans=max(ans,area(g[i],g[j],g[k]));
     
    for(int i=0;i<b.size();++i)
        for(int j=i+1;j<b.size();++j)
            for(int k=j+1;k<b.size();++k)
                ans=max(ans,area(b[i],b[j],b[k]));
     
    for(int i=0;i<r.size();++i)
        for(int j=0;j<g.size();++j)
            for(int k=0;k<b.size();++k)
                ans=max(ans,area(r[i],g[j],b[k]));
     
    printf("%.5lf",ans);
    return 0;
}

------------------------------------------------------------------------------------------------

第二题

一个数轴上共有N个点,第一个点的坐标是度度熊现在位置,第N-1个点是度度熊的家。现在他需要依次的从0号坐标走到N-1号坐标。
但是除了0号坐标和N-1号坐标,他可以在其余的N-2个坐标中选出一个点,并直接将这个点忽略掉,问度度熊回家至少走多少距离?

输入描述:
输入一个正整数N, N <= 50。

接下来N个整数表示坐标,正数表示X轴的正方向,负数表示X轴的负方向。绝对值小于等于100
输出描述:
输出一个整数表示度度熊最少需要走的距离。
示例1
输入
4
1 4 -1 3
输出
4
分析:

第一遍遍历算出未忽略一个点需要的总路程

第二次遍历计算中间每个点 如果被忽略能节省的路程

    节省的路程 = 原先左右两点经过该点的距离和 - 去除该点后左右两点的直接距离

最小路程 = 总路程 - 能省下的最大路程

完整代码
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
int main()
{
    vector<int>dis;
    int n,temp;
    cin>>n;
    for(int i=0;i<n;++i)
    {
        cin>>temp;
        dis.push_back(temp);
    }
    int total=0;
    for(int i=1;i<n;++i)total+=(abs(dis[i]-dis[i-1]));    //计算总路程
    int maxles=0;
    for(int i=1;i<n-1;++i)
    {
        temp=abs(dis[i]-dis[i-1])+abs(dis[i]-dis[i+1])-abs(dis[i+1]-dis[i-1]);    //计算忽略每个点能省下的路程
        if(maxles<temp)maxles=temp;
    }
    cout<<total-maxles<<endl;
     
}

------------------------------------------------------------------------------------------------

第一题

度度熊想去商场买一顶帽子,商场里有N顶帽子,有些帽子的价格可能相同。度度熊想买一顶价格第三便宜的帽子,问第三便宜的帽子价格是多少?

输入描述:
首先输入一个正整数N(N <= 50),接下来输入N个数表示每顶帽子的价格(价格均是正整数,且小于等于1000)
输出描述:
如果存在第三便宜的帽子,请输出这个价格是多少,否则输出-1
示例1
输入
10
10 10 10 10 20 20 30 30 40 40
输出
30
分析 :

题意可以理解为:在去重的情况下,求第 k 小的数

但是本题的 k 取值恒为 3 ,只要第三小的,因此很多方法都可以,效率都很接近

我采用 std::set ,因为该数据结构本身是去重的并且有序,还可以采用维护一个大顶堆(N和k 较大时,priority_queue)

完整代码
#include<stdio.h>
#include<set>
using namespace std;
 
int main()
{
    int n,i,temp;
    scanf("%d",&n);
    set<int>price;
    for(i=0;i<n;i++)
    {
        scanf("%d",&temp);
        price.insert(temp);
    }
    if(price.size()<3)printf("-1");
    else
    {
        auto it=price.begin();
        for(i=0;i<2;i++,it++);
        printf("%d",*it);
    }
     
    return 0;
}






猜你喜欢

转载自blog.csdn.net/bobbymly/article/details/79603876
今日推荐