【清华软院机试】2015年预推免机试题及题解

2015年题目收集来自这位博主的专栏【链接】
代码本身比博主的较为精简,更易初学者读懂。后期会更新其他几年题目


题目分类

  • 病毒感染:模拟题
  • 算式: DFS
  • 航线交叉:区间DP

题目1:病毒感染

在这里插入图片描述
二刷简洁代码
直接打印了每个时间的病毒个数,为便于debug。

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
int n,m,t1,t2,k,cnt=0;
int a[50][50],vis[50][50];
int go[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
vector<int> atk;
void attack(int a1,int b1)
{
   for(int i=0;i<4;i++)
   {
       int a2=go[i][0]+a1;
       int b2=go[i][1]+b1;
       if(a2>=0&&a2<n&&b2>=0&&b2<m)
        //边界要求
       if(a[a2][b2]==0&&vis[a2][b2]==1)
       {
           cnt++;
           a[a2][b2]=1;
       }
   }
}
void defend(int a1,int b1)
{
    vis[a1][b1]=0;
    a[a1][b1]=0;
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    fill(a[0],a[0]+2500,0);
    fill(vis[0],vis[0]+2500,1);
    for(int i=0;i<k;i++){
       scanf("%d %d",&t1,&t2);
       a[t1-1][t2-1]=1;
       cnt++;
    }
    while(cnt!=0)
    {
        for(int i=0;i<n;i++)
          for(int j=0;j<m;j++)
        {
            if(a[i][j]!=0)
            {
              a[i][j]++;
            }
            if(a[i][j]==4)
            {
               atk.push_back(i);
                atk.push_back(j);
            }
            else if(a[i][j]==6)
            {
                cnt--;
                defend(i,j);
            }
        }
        //结束循环以后进行感染
        for(int i=0;i<atk.size();i+=2)
            attack(atk[i],atk[i+1]);
        atk.clear();
        printf("%d\n",cnt);
    }
    return 0;
}

一刷代码
需要注意当为4时,需要直接向外扩展;并且为防止遍历过程中,感染周围的人也被重复计算,我这里是通过给队列,在遍历之后,在进行感染操作。判断时为上一阶段的条件,即之前为3即可感染,之前为5即可治疗。(也可以考虑先状态++,再进行相应的判断)

#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
int a[15][15],ka[15][15];
int go[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
int n,m,k,t1,t2,num=0;
int rungo(int i,int j)
{
    int tmpn=0;
    for(int z=0;z<4;z++)
    {
        t1=i+go[z][1];
        t2=j+go[z][0];
        if(t1>=1&&t1<=n&&t2>=1&&t2<=m&&a[t1][t2]==0&&ka[t1][t2]==0)
         {
             a[t1][t2]=1;
             //printf("上下左右: %d %d\n",t1,t2);
//             如果往后找,后的值已经被计数过,所以需要返回传染值
//             if(z%2==1)
             tmpn++;
         }
    }
    //printf("传染: %d\n",tmpn);
    return tmpn;
}
int run()
{
    int nmax=0;
    while(num!=0)
    {
        num=0;
        vector<int> gan;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            //病毒滋生
            if(ka[i][j]==0)
            {
              if((a[i][j]>0&&a[i][j]<3)||a[i][j]==4)
             {
                //printf("对应的点:%d %d %d\n",i,j,a[i][j]);
                num++;
                a[i][j]++;
              }
            //病毒感染
            else if(a[i][j]==3)
            {
               //printf("对应的点:%d %d %d\n",i,j,a[i][j]);
               num++;
               a[i][j]++;
               gan.push_back(i);
               gan.push_back(j);
            }
            //病毒治疗
            else if(a[i][j]==5)
            {
                a[i][j]=0;
                //抗体函数
                ka[i][j]=1;
            }
        }
        for(int i=0;i<gan.size();i+=2)
        {
            int gi=gan[i],gj=gan[i+1];
            num+=rungo(gi,gj);
        }
        if(nmax<num)nmax=num;
        printf("%d\n",num);
    }
}
int main()
{
    fill(a[0],a[0]+15*15,0);
    fill(ka[0],ka[0]+15*15,0);
    scanf("%d %d %d",&n,&m,&k);
    for(int i=0;i<k;i++)
    {
      scanf("%d %d",&t1,&t2);
       a[t1][t2]=1;
       num++;
    }
    run();
    return 0;
}

2015年 题目2:

题目2:找到算式

在这里插入图片描述
在这里插入图片描述
二刷代码
时间原因,省略了打印结果,但已存到res中

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
int n,num,a[50],cnt=9999999;
vector<int> qu,res;
//只把符号入队列
void dfs(int t)
{
    if(t==n-1)
    {
       int tmp_cnt=a[0];
       for(int i=0;i<qu.size();i++)
        if(qu[i]==0) tmp_cnt+=a[i+1];
        else tmp_cnt*=a[i+1];
       //如果比预期值大于等于,并且较小
       if(tmp_cnt>=num&&tmp_cnt<cnt)
       {
           res=qu;
           cnt=tmp_cnt;
       }
       qu.pop_back();
       return ;
    }
    qu.push_back(0);
    dfs(t+1);
    qu.push_back(1);
    dfs(t+1);

    qu.pop_back();
}
int main()
{
    scanf("%d %d",&n,&num);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    dfs(0);
    printf("%d\n",cnt);
    return 0;
}
//4 235
//34 12 5 5

题解:模拟题(题目1)是真的烦啊啊啊,这题想到用dfs的话,会非常简单,10几分钟就能得到答案。清华的机试感觉数据并不是非常大,PAT是真的坑,非要搞边界。唯一提醒的就是需要再递归的时候,将符号出栈,这样可以实现很好的递归效果。

#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
int a[15],b[15];
vector<int> que,res;
int n,d,minv=999999;
void dfs(int i)
{
     if(i==n+1)
     {
         if(b[i-1]>=d&&minv>b[i-1])
         {
          minv=b[i-1];
          res=que;
         }
         return ;
     }
     b[i]=a[i]*b[i-1];
     que.push_back(0);
      dfs(i+1);
     que.pop_back();

     b[i]=a[i]+b[i-1];
     que.push_back(1);
      dfs(i+1);
     que.pop_back();
}
int main()
{
    scanf("%d %d",&n,&d);
    for(int i=1;i<=n;i++)
     scanf("%d",&a[i]);
    b[0]=1;
    dfs(1);
    if(minv!=d)
     printf("%d\n",minv);
    else
    {
        for(int i=1;i<res.size();i++)
        {
           printf("%d",a[i]);
           if(res[i]==0) printf("*");
           else printf("+");
        }
        printf("%d\n",a[n-1]);
    }
    return 0;
}

题目3:

题目3:航线交叉

在这里插入图片描述

难点在如何思考出为最长上升子序列:1.最直观的感觉就是在有序的排列航线点时要不能交叉。 2.于是,不交叉=当前面点的南点为i时,后面点的南点j,需要满足j>i(不可能等于,因为题目规定) 3.所以成了最长上升子序列
类似桶排序的做法,把北边固定的前提下,计算一个子序列中上升的个数。做法按最简单的n^2做的,后期看看优化。
状态
dp[i]表示以位置i结尾的最上升子序列长度
方程
dp[i]=1+max{ dp[j] } (j<i且a[j]<a[i])
二刷代码

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
int n,t2,t1,a[500],dp[500],maxv=-1;

int main()
{
    scanf("%d",&n);
    fill(a,a+500,0);
    fill(dp,dp+500,1);
    //dp初始化
    for(int i=0;i<n;i++)
    {
       scanf("%d %d",&t1,&t2);
       a[t1]=t2;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
    {

        if(a[i]>a[j])
         dp[i]=max(dp[j]+1,dp[i]);
        maxv=max(maxv,dp[i]);
    }
    printf("%d\n",n-maxv);
    return 0;
}
//4 235
//34 12 5 5
#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
vector<int> a,dp;
int n,d,t1,t2,minv=-1;

int main()
{
    scanf("%d",&n);
    a.resize(n+1);
    dp.resize(n+1);
    for(int i=1;i<=n;i++)
    {
      scanf("%d %d",&t1,&t2);
      a[t1]=t2;
    }
    //初始化
    fill(dp.begin(),dp.end(),0);
    dp[1]=1;

    //状态转移
    for(int i=2;i<=n;i++)
    {
      for(int j=1;j<=i;j++)
      {
          //这一段表示,存在递增关系
          if(a[i]>a[j])
            dp[i]=max(dp[i],dp[j]);
      }
      //将存在递增里,取最长的序列
      dp[i]=dp[i]+1;
      if(minv<dp[i]) minv=dp[i];
    }
    printf("%d\n",n-minv);
    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哈工深cs预推免机试题是哈尔滨工业大学(深圳)计算科学与技术专业预推免研究生的机试题目。根据题目提供的信息,我无法具体列举出所有的题目,但可以就预推免机试题的一般内容进行简要介绍。 预推免机试题一般包括以下几个方面的内容:数据结构与算法、计算网络、操作系统、数据库和程序设计语言。在预推免机试中,会对考生的基础知识和能力进行测试,以确定是否具备进一步深入学习和研究的能力。 在数据结构与算法方面,可能会涉及到常见的数据结构,如数组、链表、栈、队列、树等,要求考生掌握它们的基本操作和应用场景。同时,还可能会涉及到各种算法,如排序算法、查找算法和图算法等,要求考生了解其原理和应用。 计算网络方面的题目可能会涉及到网络体系结构、TCP/IP协议簇、网络编程等方面的内容,要求考生了解网络的基本原理和工作制。 操作系统方面的题目可能会涉及到进程管理、内存管理、文件系统等内容,要求考生了解操作系统的基本原理和操作。 数据库方面的题目可能会涉及到数据库的基本概念、关系数据库的设计与管理、SQL语言等方面的内容,要求考生了解数据库的基本原理和应用。 程序设计语言方面的题目可能会涉及到C/C++、Java等常用编程语言的语法、数据类、面向对象编程等内容,要求考生熟悉至少一种编程语言的基本知识和编程能力。 总的来说,哈工深cs预推免机试题的目的是评估考生的计算科学与技术基础知识和能力,考察其是否具备进一步深入学习和研究的潜力。希望通过此次机试,能够选拔出具备优秀计算专业基础的考生,为哈尔滨工业大学(深圳)计算科学与技术专业的研究生培养贡献力量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值