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

题目分类:

  • 1.高精度运算
  • 2.最短路径
  • 3.DFS模拟

1.高精度立方

从控制台输入一个合法数字,打印其立方

• 例如

• 输入123456789

• 输出1881676371789154860897069

• 基本编码能力、消耗时间

题解
先进行计算,第二步处理进位问题。为方便进位操作,高精度存储时低位在前,高位在后。高精度乘法:1.i位与j位相乘,数字会放在i+j位置上。 2.处理每一位的进位问题。
模板见:【链接】

加法【链接】

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
string s1;
int a[99999];
int b[99999],c[99999];
int main()
{
    getline(cin,s1);
    fill(a,a+99999,0);
    fill(b,b+99999,0);
    fill(c,c+99999,0);
    int k=0,n=s1.size();
    for(int i=n-1;i>=0;i--)
        a[k++]=s1[i]-'0';
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
           b[i+j]+=a[i]*a[j];
    //处理进位,位数与0的双检测
    k=0;
    while(b[k]!=0||k<(n-1)+(n-1))
    {
        if(b[k]>10)
        {
            b[k+1]+=b[k]/10;
            b[k]=b[k]%10;
        }
        k++;
    } 
    for(int i=0;i<n;i++)
        for(int j=0;j<k;j++)
           c[i+j]+=a[i]*b[j];
    //处理进位,位数与0的双检测
    int k2=0;
    while(c[k2]!=0||k2<(n-1)+(k-1))
    {
        if(c[k2]>10)
        {
            c[k2+1]+=c[k2]/10;
            c[k2]=c[k2]%10;
        }
        k2++;
    }
    for(int i=k2-1;i>=0;i--)
        printf("%d",c[i]);
    return 0;
}
//4 235
//34 12 5 5

2.最短路径

从控制台输入n+1 行,前n 行每行3 个整数,形如“A B d”,表示从节点A 到节点B 距离为d(双向)。第n+1 行形如“A B”,表示求A 到B 的最短距离。输出此最短距离。
• 例如:
1 42 3
42 789 4
1 789 9
1 789
输出
7
• BFS、动态规划、剪枝、图

题解
这个也迷惑行为,因为没见过题目,也不大清楚究竟考点在哪。。。01规划??反正看到题目想到的也是Djistra算法。。。这里用map作为去重找点的方法,并用索引给边权,原因是直接遍历比较大。

#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
int t1,t2,i=3,j=1;
int t,start,end1,a[500][500];
map<int,int> mp;
int main()
{
    while(i>0)
    {
        scanf("%d %d %d",&t1,&t2,&t);
        if(mp[t1]==0) mp[t1]=j++;
        if(mp[t2]==0) mp[t2]=j++;
        a[mp[t1]][mp[t2]]=a[mp[t2]][mp[t1]]=t;
        i--;
    }
    scanf("%d %d",&start,&end1);
    start=mp[start];
    end1=mp[end1];
    int n=j-1;
    int vis[n+1],dis[n+1];

    //初始化
    fill(vis,vis+n+1,0);
    fill(dis,dis+n+1,9999999);
    dis[start]=0;
    //printf("%d",n);
    for(int i=0;i<n;i++)
    {
       //寻找最小的点
       int maxv=99999999,maxi;
       for(int j=1;j<=n;j++)
            if(dis[j]<maxv&&vis[j]==0)
       {
           maxv=dis[j];
           maxi=j;
       }

       //设置为访问点
       vis[maxi]=1;
       //printf("%d \n",maxi);
       for(int j=1;j<=n;j++)
        if(dis[j]>dis[maxi]+a[maxi][j]&&vis[j]==0)
         dis[j]=dis[maxi]+a[maxi][j];
    }
    printf("%d\n",dis[end1]);
    return 0;
}

3.四则运算问题

从控制台输入一行,形如“n A1 A2 A3 … An B”。其中n代表操作数总数,A1~An 表示n 个操作数。B 代表目标数字。在此n 个操作数中以任意顺序插入n-1 个四则运算操作符,不能插入括号,形成的表达式能否得到B?能——输出1,不能——输出0。操作数和目标数字是整数,整数大小限制在32 位有符号整数范围内。
• 例如:
4 75 4 18 8 21
输出1 (75 / 4 + 18 / 8 = 21)
• 表达式求值、DFS(回溯)、栈、树

二刷代码
用一个vector代替栈,将*/先进行计算,再计算对应的+ -,总体使用dfs框架。需要注意21计算时需要浮点的精度四舍五入才能得到运算结果。

#include<cstdio>
#include<iostream>
#include<map>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
int a[99999],n,num,flag=0;
//1.2 +- 3.4 */
int fuhao[4]={-1,-2,-3,-4};
vector<double> b,st,tmpst,bres;
void print(int cnt)
{
    printf("%d",a[0]);
    for(int i=0;i<bres.size();i++)
    {
        if(bres[i]==-1) printf("*");
        else if(bres[i]==-2) printf("/");
        else if(bres[i]==-3) printf("+");
        else printf("-");
        printf("%d",a[i+1]);
    }
    printf("=%d\n",cnt);
}
void dfs(int t)
{
    if(t==n)
    {
        tmpst.clear();
        bres.clear();
        bres=b;
        tmpst.push_back(a[0]);
        //printf("%d %d\n",b.size(),t);
        for(int i=0;i<n;i++)
        {
            if(b[i]>=-2)
            {
                //*,/
                if(b[i]==-1) tmpst[tmpst.size()-1]*=a[i+1];
                else if(b[i]==-2) tmpst[tmpst.size()-1]/=a[i+1];
            }
            else
            {
              tmpst.push_back(b[i]);
              tmpst.push_back(a[i+1]);
            }
        }
        //printf("111\n");
        double cnt=tmpst[0];
        for(int i=1;i<tmpst.size();i+=2)
        {
             if(tmpst[i]==-3) cnt+=(double)tmpst[i+1];
             else cnt-=(double)tmpst[i+1];
        }
        if(cnt==num)
        {
            flag=1;
            printf("1\n");
            print(cnt);
        }
        b.pop_back();
        return ;
    }
    for(int i=0;i<4;i++)
    {
       b.push_back(fuhao[i]);
       dfs(t+1);
    }
    b.pop_back();
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    scanf("%d",&num);
    dfs(1);
    if(flag==0)
        printf("0\n");
    return 0;
}
//4 235
//34 12 5 5

题解
个人感觉是个dfs的模拟题,可以用两个数组去做。我这个emmmm反正写是写出来了,但感觉不是很好。原博主的似乎是个模板。类似于表达式的双栈解决。但感觉代码量相差不太大。

#include<cstdio>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
using namespace std;
int t1,t2,i=3,j=1;
int n,k,a[500];
int b[4]={0,1,2,3};
vector<float> res,res2,a2,ans2,c;
void dfs(int i)
{
   if(i==n-1)
   {
       int vis[a2.size()],ans=0;
       fill(vis,vis+a2.size(),1);
       c.clear();
       res.clear();
       res2.clear();
       for(int i=0;i<n;i++)
        c.push_back(a[i]);
       //先做乘除法,并通过vis给出剩余数字
       for(int j=0;j<a2.size();j++)
          if(a2[j]==2){
            c[j+1]=c[j]*c[j+1];
            vis[j]=0;
          }
          else if(a2[j]==3)
          {
            c[j+1]=c[j]/c[j+1];
            vis[j]=0;
          }
       //剩余数字放入res
       for(int j=0;j<a2.size();j++)
            if(vis[j]==1){
              res.push_back(c[j]);
              res2.push_back(a2[j]);
            }
       res.push_back(c[n-1]);
      //做加减法
      for(int j=0;j<res2.size();j++)
        {
            if(res2[j]==0) res[j+1]=res[j]+res[j+1];
            else res[j+1]=res[j]-res[j+1];
        }
       if(res[res.size()-1]==k)
       {
        for(int j=0;j<n-1;j++)
        {
         cout<<a[j];
         if(a2[j]==0)cout<<"+";
         else if(a2[j]==1) cout<<"-";
         else if(a2[j]==2) cout<<"*";
         else if(a2[j]==3) cout<<"/";
        }
        cout<<a[n-1]<<"="<<res[res.size()-1]<<endl;
       }
       return ;
   }
   for(int j=0;j<=3;j++)
   {
       a2.push_back(b[j]);
       dfs(i+1);
       a2.pop_back();
   }
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&k);
    dfs(0);
    return 0;
}
//4 75 4 18 8 21
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值