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

题目分类

  • 火星进位:高精度加法
  • 被遗漏的数字:DFS+模拟
  • 收集苹果:区间DP

1.火星进位

在这里插入图片描述

Sample Input
1,0 2,1
4,2,0 1,2,0
1 10,6,4,2,1
0 0

Sample Output
1,0,1
1,1,1,0
1,0,0,0,0,0

题解

模拟题写起来比较麻烦,建议看杭电佬的题解。这是一道类似高精度加法的问题,需要注意字符串读取的时候,多位的处理,以及高精度加法的模板熟悉程度。题目原地址【链接】

#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
int prim[30];
void prime()
{
    for(int z=0,i=2;z<=26;i++)
    {
        int flag=1;
        for(int j=2;j<=sqrt(i);j++)
        if(i%j==0) {
            flag=0;
            break;
        }
        if(flag==1)
            prim[z++]=i;
    }
}
int main()
{
    string s1,s2;
    vector<int> a1,a2,a3;
    prime();
    while(1)
    {
        cin>>s1>>s2;
        if(s1[0]=='0'&&s2[0]=='0')
            break;
        else
        {
          a1.clear(),a2.clear(),a3.clear();
          reverse(s1.begin(),s1.end());
          reverse(s2.begin(),s2.end());
          int i=0;
          while(i<s1.size())
          {
              int num=0,k=0;
              while(s1[i]!=','&&i<s1.size())
              {
                 num+=(s1[i]-'0')*pow(10,k);
                 k++;
                 //printf("%d\n",num);
                 i++;
              }
              a1.push_back(num);
              i++;
          }
          i=0;
          while(i<s2.size())
          {
              int num=0,k=0;
              while(s2[i]!=','&&i<s2.size())
              {
                 num+=(s2[i]-'0')*pow(10,k);
                 k++;
                 //printf("%d\n",num);
                 i++;
              }
              a2.push_back(num);
              i++;
          }
          a3.resize(30);
//          for(int i=0;i<a2.size();i++)
//            cout<<a2[i]<<endl;
        for(i=0;i<a1.size()||i<a2.size();i++)
        {
          int t=a3[i];
          if(i<a1.size()) t+=a1[i];
          if(i<a2.size()) t+=a2[i];
          a3[i+1]+=t/prim[i];
          a3[i]=t%prim[i];
         }
     //进位情况
     while(a3[i+1]!=0)
    {
        a3[i+1]=a3[i]/prim[i];
        a3[i]=a3[i]%prim[i];
        //printf("进位:%d %d\n",i,a3[i]);
    }
    while(i>0)
        cout<<a3[i--]<<",";
    cout<<a3[0]<<endl;
    }

}
return 0;
}
//4 75 4 18 8 21

2.被遗漏的数字

Problem Description
小明写了一个函数,将1-n 的数随机排列组成一个字符串,每个数字使用且仅使用一次。但是小明在写的时候粗心了,导致生成的字符串丢失了其中一个数字。帮助小明找出这个数字

Input
测试输入包含若干测试用例,每个测试用例占两行,第一行是n(2<=n<=200),第二行是一个字符串。
Output
对每个测试用例输出1 行,输出缺漏的数字

Sample Input
5
1234
20
12345678910111314151617181920

Sample Output
5
12

题解
DFS+模拟题,这个题的代码并没有很好的实现。。。。没有理解佬们的解题思路。代码的思路是通过桶排序,给出对应的数字出现个数,然后和字符串相减给出缺失数字,然后全排列缺失数字。在字符串中出现对应顺序的排列认为已经存在。找出未出现的顺序。
出现的问题:
1.全排列需要比n小,如12的全排列,21不符合要求
2.出现的顺序可能为零散的数字,如样例2中12被作为1,2也出现了,就无法处理这种情况。
博主放弃了,看不懂题解也感觉再纠结用处不大。后期有时间再二刷吧。

#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
int n,k=0;
string s1;
vector<int> ans[50],tmpans,s2,ansnum;
void dfs(vector<int> &vis,vector<int> &res,int i,int n)
{
    vis[i]=1;
    tmpans.push_back(res[i]);
    //printf("放入%d\n",i);
    if(n==res.size())
    {
      if(tmpans[0]!=0)
        ans[k++]=tmpans;
      //cout<<"打印成功"<<endl;
    }
    else
    {
        for(int j=0;j<res.size();j++)
            if(vis[j]==0) dfs(vis,res,j,n+1);
    }
    tmpans.pop_back();
    //printf("弹出%d\n",i);
    vis[i]=0;
}
int main()
{
   while(scanf("%d\n",&n)!=EOF)
   {
      vector<int> a(10),res;
      ans[50].clear();
      tmpans.clear();
      s2.clear();
      ansnum.clear();
      cin>>s1;

      //计算原有
      for(int i=1;i<=n;i++)
      {
          int t=i;
          while(t>=10)
          {
              a[t%10]++;
              t=t/10;
          }
          a[t]++;
      }
      for(int i=0;i<s1.size();i++) a[s1[i]-'0']--;
      for(int i=0;i<s1.size();i++) s2.push_back(s1[i]-'0');
      for(int i=0;i<=9;i++)
//        printf("%d\n",a[i]);
        while(a[i]!=0)
      {
         res.push_back(i);
         a[i]--;
      }
      vector<int> vis(res.size());
      for(int i=0;i<res.size();i++)
          dfs(vis,res,i,1);
      ansnum.resize(k);
      for(int i=0;i<s2.size();i++)
      {
          for(int j=0;j<k;j++)
            if(ans[j][0]==s2[i])
          {
              int z=1,flag=0;
              while(z<ans[j].size())
              {
                 if(ans[j][z]!=s2[i+z]) flag=1;
                 z++;
              }

              if(flag==0) ansnum[j]=1;
          }
      }
      int tmp;
      for(int i=0;i<k;i++)
        if(ansnum[i]==0)
            {tmp=i;break;}
         for(int j=0;j<ans[tmp].size();j++)
            printf("%d",ans[tmp][j]);
          printf("\n");
   }

return 0;
}

3.收集苹果

平面上有N*M个格子,每一个格子中放着一定数量的苹果。

你从左上角的格子開始,每一步仅仅能向下走或是向右走,每次走到一个格子上就把格子里的苹果收集起来,这样下去。你最多能收集到多少个苹果。

输入:

第一行输入行数和列数

然后逐行输入每一个格子的中的苹果的数量

输出:

最多能收到的苹果的个数。

题解
这个题就非常简单,是个简单的区间DP,每个位置a[i][j]为上一个和左边一个里最大的那个加上本身可以获得的苹果数。注意需要在边缘填充0,以防止边缘的结果无法通过状态方程进行转移。总的来说题目3非常简单,相比之下1.2有点小难。。。

#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
int n,m;
int a[999][999];
int main()
{
   //初始化,边缘值需要填充0,以防边缘无法进行递推

   cin>>m>>n;
   for(int i=0;i<=n;i++)
     a[i][0]=0;
   for(int j=0;j<=m;j++)
     a[0][j]=0;

   for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        scanf("%d",&a[i][j]);
   for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
       a[i][j]+=max(a[i-1][j],a[i][j-1]);
    printf("%d\n",a[n][m]);
return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值