链家 2018校招 笔试编程题

版权声明:本人ZZU在校学生,文章均为个人心得,有不足之处请不吝赐教! https://blog.csdn.net/whl_program/article/details/81880571

编程题一:
玥玥带乔乔一起逃亡,现在有许多东西要放到乔乔的包里面,但是包的大小有限,所以我们只能够在里面放入非常重要的物品.现在给出该种物品的数量,体积,价值的数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,乔乔会非常感谢你的
对于30%的数据
1<=n<=2000 1<=v<=500
1<=m<=10 1<=w<=20 1<=s<=100

输入
第 1 行有两个整数,物品种数 n 和背包装载体积v;
第 2 到 n+1 行每行三个整数,为第 i 种物品的数量m, 体积w,价值s
输出
仅包含一个整数,即为能拿到的最大的物品价值总和

Input
2 10
3 4 3
2 2 5
Output
13

思路:
动态规划

空间复杂度O(c*v)

#include <bits/stdc++.h>//包含C++的所有头文件
using namespace std;

int n, v, m, w[20001], s[20001];
int c=0;//c为物品总个数
int res[20001][501];//res[i][j]表示物品为1到i个,体积为j的情况下背包最大价值 空间复杂度O(c*v)
int main()
{
    memset(res,0,sizeof res);//对value清零
    scanf("%d %d", &n, &v);
    for(int i=1,j=1; i<=n; i++){
        scanf("%d %d %d", &m, &w[j], &s[j]);
        c += m;
        for(int k=1; k<m; k++){
            w[j+k] = w[j];
            s[j+k] = s[j];
        }
        j += m;
    }
    for(int i=1; i<=c; i++){
        for(int j=1; j<=v; j++){
            int k = j-w[i];
            res[i][j] = (k>=0 ? max(res[i-1][k]+s[i], res[i-1][j-1]) : res[i-1][j-1]);
        }
    }
    cout << res[c][v] << endl;
    return 0;
}

优化空间复杂度

#include <bits/stdc++.h>//包含C++的所有头文件
using namespace std;

int n, v, m, w[20001], s[20001];
int c=0;//c为物品总个数
int simple[501];//simple[v]表示物品为1到c个,体积为v的情况下背包最大价值 空间复杂度减小到O(v)
//空间复杂度减小到O(v)
int main()
{
    memset(simple,0,sizeof simple);//对value清零
    scanf("%d %d", &n, &v);
    for(int i=1,j=1; i<=n; i++){
        scanf("%d %d %d", &m, &w[j], &s[j]);
        c += m;
        for(int k=1; k<m; k++){
            w[j+k] = w[j];
            s[j+k] = s[j];
        }
        j += m;
    }
    for(int i=1; i<=c; i++){
        for(int j=v; j>=0; j--){
            int k = j-w[i];
            simple[j] = (k>=0 ? max(simple[k]+s[i], simple[j-1]) : simple[j-1]);
        }
    }
    cout << simple[v] << endl;
    return 0;
}

编程题二:
小明喜欢在火车旅行的时候用手机听音乐,他有 N 首歌在手机里,在整个火车途中,他可以听 P 首歌,所以他想产生一个播放表产生 P 首歌曲,这个播放表的规则是:
· 每首歌都要至少被播放一次
· 在两首一样的歌中间,至少有M首其他的歌
迈克在想有多少种不同的播放表可以产生,那么给你 N,M,P,你来算一下,输出结果取1000000007的余数

输入
输入 N,M,P
N 范围在 1 到 100
M 范围在 0 到 N
P 范围在 N 到 100
输出
输出结果 mod 1000000007 的余数

Input
1 0 3
Output
1

思路:
定义 List(i,j) 为安排列表中有 i 首歌时,已经用了 j 首不同歌, 此时的安排种类数
当 j>i 时,列表短但是歌曲过多,不合题意,所以种类数为0
当 j==i 时, 全排列 A(n,n)

另外,当 j>m 时就可以出现重复了,有两种安排方法,添加新歌,添加重复歌,所以其值就是这两种情况的和

  • 添加新歌
    List[i][j] = List[i-1][j-1]*(n-j+1);
  • 添加重复歌
    当 j<=n 时添加重复歌曲的种类为 songList(i-1,j)*(j-m)
    当 j>n 时添加重复歌曲的种类为 songList(i-1,j)*(n-m), 因为一共就 n 首歌
    最后List(n,p) 即为所求
#include <iostream>
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 1000000007
using namespace std;

ll n,m,p,List[105][105];
int main()
{
    while(cin >> n >> m >> p){
        memset(List, 0, sizeof List);
        List[0][0] = 1;//为了计算全排列设置的值
        for(ll i=1; i<=p; i++){//列表
            for(ll j=1; j<=n; j++){//歌
                if(j > i){//歌比列表多
                    List[i][j] = 0;
                }else if(j == i){
                    List[i][j] = List[i-1][j-1]*(n-j+1);
                }else if(j > m){
                    List[i][j] = List[i-1][j-1]*(n-j+1) + List[i-1][j]*(min(j,n)-m);
                }else{
                    List[i][j] = 0;
                }
                if(List[i][j] >= inf)
                    List[i][j] %= inf;
            }
        }
        for(ll i=0; i<=p; i++){//列表
            for(ll j=0; j<=n; j++){//歌
                   cout << List[i][j] << " ";
            }
            cout << endl;
        }
        cout << List[p][n] << endl;
    }

    return 0;
}

优化空间复杂度为O(n)

#include <iostream>
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 1000000007
using namespace std;

ll n,m,p,songList[105];
int main()
{
    while(cin>>n>>m>>p)
    {
        memset(songList,0,sizeof songList);
        songList[0]=1;
        for(ll i=1;i<=p;++i)
        {
            for(ll j=n;j>=0;--j)
            {
                if(j>i)
                    songList[j]=0;
                else if(j==i)
                    songList[j]=songList[j-1]*(n-j+1);
                else if(j>m)
                    songList[j]=songList[j-1]*(n-j+1)+songList[j]*(min(j,n)-m);
                else
                    songList[j]=0;
                if(songList[j]>=inf) songList[j]%=inf;
            }
            for(ll j=0;j<=n;++j)
            {
                cout<<songList[j] << " ";
            }
            cout << endl;
        }
        cout<<songList[n]<<endl;
    }
    return 0;
}

编程题三:
小明有 n( 1<=n<=2000 )个美味的食物,他想卖掉它们来赚钱.
这些食物放在一些箱子里,他们有些有趣的特性
1. 这些食物被编号为 1~n,每一天小明可以从这些箱子的头部或者尾部取出食物去卖
2. 这些食物放得越久,年龄越大,价值越大,食物 i 有一个初始的价值 v(i)
3. 放了 a 天后年龄为 a ,食物最终价值为 v(i)*a
给定每一个食物的初始价值v(i),请求出小明卖掉它们后可以获得的最大价值,第一天出售的食物的年龄为 1,此后每增加一天食物的年龄就加 1

输入
第 1 行:一个整数 n
第 2 到第 n+1 行:每个食物的初始价值 v(i)

输出
1 行:小明最终可以获得的最大价值

提示
样例说明:小明出售这些食物(初始价值1,3,1,5,2)的顺序为:
第一天卖掉第1个,
第二天卖掉第5个,
第三天卖掉第2个,
第四天卖掉第3个,
第五天卖掉第4个,获得最大的价值

1*1+2*2+3*3+4*1+5*5=43.

思路:
income[i][j] 表示还有第i个到第j个没卖出时,已经得到的最大收入
income[i][j] = max( income[i-1][ j]+food[i-1]*day, income[ i][ j+1]+food[j+1]*day )

#include <bits/stdc++.h>
using namespace std;
int n,food[2002],income[2002][2002],day,maxIncome;

int main()
{
    memset(income,0,sizeof income);
    maxIncome=0;
    cin>>n;
    food[0]=food[n+1]=0;
    for(int i=1;i<=n;++i)
    {
        cin >> food[i];
    }
    for(int i=1; i<=n; ++i)
    {
        day=i-1;
        for(int j=n;j>=i;--j)
        {
            income[i][j] = max(income[i-1][j]+food[i-1]*day, income[i][j+1]+food[j+1]*day);
            ++day;
        }
        maxIncome=max(maxIncome,income[i][i]+food[i]*n);
    }
    cout << maxIncome;
    return 0;
}

优化空间复杂度O(n)

#include <bits/stdc++.h>
using namespace std;
int n,food[2002],income[2002],day,maxIncome;
//income( i,j )=max( income( i-1,j )+food[i-1]*day,income( i,j+1 )+food[j+1]*day )
int main()
{
    memset(income,0,sizeof income);
    maxIncome=0;
    cin>>n;
    food[0]=food[n+1]=0;
    for(int i=1;i<=n;++i)
    {
        cin>>food[i];
    }
    for(int i=1;i<=n;++i)
    {
        day=i-1;
        for(int j=n;j>=i;--j)
        {
            income[j]=max(income[j]+food[i-1]*day,income[j+1]+food[j+1]*day);
            ++day;
        }
        maxIncome=max(maxIncome,income[i]+food[i]*n);
    }
    cout<<maxIncome;
    return 0;
}

其他思路,点击链接

编程题四
在迷迷糊糊的大草原上,小红捡到了n根木棍,第i根木棍的长度为i,小红现在很开心。她想选出其中的三根木棍组成美丽的三角形。但是小明想捉弄小红,想去掉一些木棍,使得小红任意选三根木棍都不能组成三角形。请问小明最少去掉多少根木棍呢?
输入
本题包含若干组测试数据。

对于每一组测试数据。
第一行一个n,表示木棍的数量。

满足 1<=n<=100000

输出
输出最少数量

样例输入
4
样例输出
1

本题思路很简单,其实就是一个斐波那契数列的问题
因为有多组参数,所以先用打表法,先求出100000以内从1、2、3开始的斐波那契数列
然后进行根据输入的n,查找小于等于n的斐波那契数列元素有res个,最终输出结果就是n-res。

注意本题是多组输入。

#include <iostream>
#include <vector>
#define TOP 100000
using namespace std;

int main()
{
    vector<int> res = {0, 1, 2};
    for(int i=3; res[i-1]+res[i-2]<=TOP; i++)
        res.push_back(res[i-1]+res[i-2]);
    for(int n; cin>>n; ){//多组输入
        //函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。
        //如果所有元素都小于val,则返回last的位置
        vector<int>::iterator it = lower_bound(res.begin(), res.end(), n);
        int temp = (*it==n ? 0 : *it-n-1);//没有在斐波那契数列中找到n,减去temp
        cout << *it - (it-res.begin()) - temp << endl;
    }
    return 0;
}

编程题五:
在小红家里面,有n组开关,触摸每个开关,可以使得一组灯泡点亮。
现在问你,使用这n组开关,最多能够使得多少个灯泡点亮呢?

输入
第一行一个n,表示有n组开关。
接下来n行,每行第一个整数为k,表示这个开关控制k个灯泡,接下来k个整数,表示控制的灯泡序号。

满足:
1<=n<=1000
1<=k<=1000
序号是在int范围内正整数。

输出
输出最多多少个灯泡点亮。

输入
2
2 1 2
2 2 3
输出
3

输入
3
1 1
1 2
2 1 2
输出
2

关键点:题目只说开关点亮灯泡,两个开关同时开一个灯泡,依旧灯泡是亮的
set去重即可

#include <iostream>
#include <set>
using namespace std;

int main()
{
    for(int n; cin>>n; ){
        set<int> s;
        for(int i=0; i<n; i++){
            int k; cin >> k;
            for(int j=0; j<k; j++){
                int temp;
                cin >> temp;
                s.insert(temp);
            }
        }
        cout << s.size() << endl;
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/whl_program/article/details/81880571
今日推荐