复旦计院2020机试真题

A 斗牛

 直接暴力求解即可

#include<iostream>
using namespace std;
const int N = 1010;
int a[5],sum;
bool flag;
int main(){
    int T;
    cin >> T;
    while(T--){
        for(int i = 0;i < 5;i++) cin >> a[i];
        flag = false;
        for(int i = 0;i <5; i++)
            if(!flag)
                for(int j = i + 1;j <5; j++)
                    if(!flag)
                        for(int k = j + 1;k < 5;k++)
                            if((a[i] + a[j] + a[k]) % 10 == 0)
                                {
                                    flag = true;
                                    sum = 0;
                                    for(int q = 0;q < 5; q++)
                                        if(q != i && q != j && q!= k)
                                            sum += a[q];
                                    cout << sum % 10 << endl;
                                    break;
                                }
        if(!flag) cout << -1 <<endl;
    }
    return 0;
}

B 打地鼠

此题重点是要看出最长选择方案中一定有最小值,则排序后从最小值开始遍历即可。我用的是set。也可以直接用sort函数排序。

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
const int N = 1e5 +10;
int n,d;
multiset<int>  a;
int main(){
    cin >> n >> d;
    for(int i = 1;i <= n;i++) {
        int x;
        cin >> x;
        a.insert(x);
    }

    auto x = *a.begin();
    int length = 1;

    while(a.lower_bound(x + d) != a.end()) { //a.lower_bound(x)的功能为输出a中大于等于x的最    
                                               小值的迭代器。若没有则输出a.end()
        x = *a.lower_bound(x + d);
        length ++;
    }

    cout <<length;
    return 0;
}

C 排队打饭

#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N],t[N],b[N];
int n;
int main(){
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> a[i] >> t[i] >> b[i];
    
    int time = a[1];
    
    for(int i = 1;i <= n;i++){
        if(a[i] + b[i] >= time){
            cout << time << ' ';
            time += t[i];
        }
        else cout << -1 << ' ';
    }
    
    return 0;
}

D 二叉搜索树

用数组存储二叉树的做法。这种做法空间复杂度过高,A不了本题。是我最开始的一种思路。

//11.51 - 12.26
#include<iostream>
using namespace std;
const int N = 1e5 +10;
int a[N],b[N]; //a数组应该开的比这个大得多,这里只是验证小数据时可以
void insert(int root,int x){  //将x插入以root节点后面
    if(x > a[root]){
        int r = root * 2 + 1;
        if(a[r]) insert(r,x);
        else {
            a[r] = x;
            b[x] = a[root];  
        }
    }
    else {
        int l = 2 * root;
        if(a[l]) insert(l,x);
        else{ 
            a[l] = x;
            b[x] = a[root];  
        }
    }
}
int main(){
    int n;
    cin >> n;
    
    int x;
    cin >> x;
    a[1] = x;
    for(int i = 2;i <= n;i++){
        cin >> x;
        insert(1,x);
    }
    
    for(int i = 1;i <= n;i++) cout << b[i] << ' ';
    return 0;
}

数组存储二叉树的改进方法。设置两个数组l[N]与r[N]。l[i]、r[i]代表i的左孩子与右孩子。其他思路与前面类似。体现了以空间换时间的方法。 

代码转自其他博客。

#include<iostream>
using namespace std;
const int N=1e5+10;
int l[N],r[N],fa[N];
int n;
int root;
void insert(int i,int root)
{
    if(i<root)  
    {
        if(!l[root])
        {
        l[root]=i;
        fa[i]=root;
        return ;
        }
        else
        {
            insert(i,l[root]);
        }
    }
    else if(i>root)
    {
        if(!r[root])
        {
        r[root]=i;
        fa[i]=root;
        return ;
        }
        else 
        {
            insert(i,r[root]);
        }
    }
}
int main()
{
    cin>>n;
    cin>>root;
    fa[root]=0;
    for(int i=1;i<n;i++)
    {
        int t;
        cin>>t;
        insert(t,root);
    }

    for(int i=1;i<=n;i++)
      cout<<fa[i]<<' ';
      cout<<endl;

    return 0;
}

用链表存储二叉树

//11.51 - 12.26
#include<iostream>
using namespace std;
const int N = 1e5 +10;
int a[N],b[N];
typedef struct Node{
    int val;
    struct Node *left,*right;
}Node;
void insert(Node *root,int x){  //将x插入以root节点后面
    if(x > root->val)    //插到右儿子
        if(root -> right) insert(root -> right,x);
        else{
            root -> right = (Node*)malloc(sizeof(Node));
            root -> right -> val = x;
            b[x] = root -> val;
        }
    else               //插到左儿子
        if(root -> left) insert(root -> left,x);
        else{
            root -> left = (Node*)malloc(sizeof(Node));
            root -> left -> val = x;
            b[x] = root -> val;
            }
          
    
}
int main(){
    int n;
    cin >> n;
    
    int x;
    cin >> x;
    Node *root =  (Node*)malloc(sizeof(Node));
    root -> val = x;
    for(int i = 2;i <= n;i++){
        cin >> x;
        insert(root,x);
    }
    
    for(int i = 1;i <= n;i++) cout << b[i] << ' ';
    return 0;
}

以上做法都需要建树。搜索二叉树最坏时间复杂度为n^2。所以估计都会超时。可能还需要优化。不过我目前的水平只能做到这里了。0.0

转自其他博客的一种思路 

E 序列

 状态定义:f[i][j]表示b数组中第i 个选j时前i个数的最小总权值。

状态划分:根据第j个数选0-9来枚举所有状态。当j确定时,还需要遍历b数组中第i-2个数的所有状态才能得出j确定时的最小值

f[i][j] = min(f[i][j],f[i - 1][k] + abs(a[i] - j) + (j - k) ^ 2

遇到的问题:

1、刚开始知道用动态规划的思路,但是思路想偏了。刚开始的思路是先确定b数组中第一个数,再确定第二个...以此类推,但发现按这个思路第一个数是无法确定的。思路想偏的原因还是对DP思想理解不透彻,DP问题关键在于将大问题分解为相似的若干可以解决的小问题,大问题的解决建立在小问题已经解决的基础上。主要方法是枚举所有方案。然后选出符合题意的方案。

2、f数组本来定义在了main函数里,结果产生了玄学错误。。。f数组的值总是不对。不知道是不是因为自己用的在线编译器的原因。排查了好久,最后把f数组定义成了全局变量就好了。这种错误真的折磨人...

#include<bits/stdc++.h>
using namespace std;

vector<int> a;
int f[10][10];
int main(){
    int n;
    cin >> n;
    for(int i = 0;i < n;i++)
        {
            int x;
            cin >> x;
            a.push_back(x);
        }    
    
    memset(f,0x3f,sizeof f);

    
    for(int i = 0;i < n;i++)
        for(int j = 0; j < 10;j++)
            if(i)
                for(int k = 0;k < 10;k++)
                    f[i][j] = min(f[i][j],f[i - 1][k] + abs(a[i] - j) + (j - k) * (j- k));
            else
                f[i][j] = abs(a[i] - j);
        
   
    int maxm = 0x3f3f3f3f;
    
    for(int i = 0;i < 10;i++){
        maxm = min(maxm,f[n - 1][i]);
    } 
    cout << maxm;
    return 0;
}

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值