杭电15年笔试真题详解

目录

题目一:

给定一个字符串,计算字符串中数值的个数并求和。其中还包含了负号,若紧跟负号的是一个数值,则表示这是一个负数,若后面跟着的不是数字,则不表示什么。输入:一个字符串输出:数值个数数值和列子
输入:312ab-2—9–a
输出:3 301
多年不写代码,现在写个这么简单的判断都如此笨拙,而且代码丑陋无比,后来的考杭电的大佬,如果有更好的思路,麻烦在下面贴出你的代码,以便大家学习
思路:
1.对这个字符串进行暴力遍历。
2.如果遍历过程中遇到“-”号,并且”-“号后面就是数字的话,那么就进入一个死循环,并且更新暴力指针,直到把这个负数完整的取出来,解除死循环,继续暴力该字符串。
3.如果遇到数字的话,那么就可以肯定他一定是正数,负数的话一定会走第二步,走不到这一步的。进入死循环,更新暴力指针,把这个字符串存储到一个临时数组中,然后使用atoi函数,将这个字符串转换成数字即可。
4.我们把2,3两步中取出来的字符串放入到一个sum数组当中。
5.把sum数组中取出来的所有正数或者负数,进行累加求和。我们就可以得到最终的结果。
方法一:

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<string.h>
using namespace std;
int main(){
    string str;
    cin>>str;
    int sum[100],sum_cnt=0; 
    char tmp[20];//中间变量,用来截取数字 
    for(int i=0;i<str.length();i++){//从头到尾开始进行遍历 
        //memset(tmp,0,sizeof(tmp));//初始化字符串 
        int tmp_cnt=0;
        if(str[i]<='9'&&str[i]>='0'){
            while(true){//处理正数 
                if(str[i]<='9'&&str[i]>='0'){
                //如果是数字,开始把这个数存储到数组里,然后走到不是数字为止。进行字符转换      
                    tmp[tmp_cnt++]=str[i];
                    i++;    
                }
                else{
                    tmp[tmp_cnt]=0;//输入字符串结束符。
                    tmp_cnt=0;//重新初始化,准备下次使用 
                    sum[sum_cnt++]=atoi(tmp);                
                    break;      
                }       
            }           
        } 
        if(str[i]=='-'&&str[i+1]<='9'&&str[i+1]>='0'){
            while(true){
                i++;//开始从数字位置开始暴力。 
                if(str[i]<='9'&&str[i]>='0'){
                //如果当前位置是负号,并且下一位是数字,将数字存储到一起   
                    tmp[tmp_cnt++]=str[i];
                }
                else{
                    tmp[tmp_cnt]=0;//输入字符串结束符。 
                    sum[sum_cnt++]=-atoi(tmp);//将取出的数值置为负数 
                    break;  
                } 
            }       
        } 
    } 
    int ans=0;      
    for(int i=0;i<sum_cnt;i++)
        ans+=sum[i];
    cout<<sum_cnt<<" "<<ans<<endl;  
    return 0;
}

0325日重新修改以上代码,套用函数将其中的取数操作变得简单化一些
方法二:

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<fstream>
#define MAX 1010
using namespace std; 
char a[1010];
char temp[1010];//该数组用来存储分隔开的整数。 
int sum[1010],sum_cnt,i;
void qushu(){
    int cnt=0;//记录数字长度 
    if(a[i]=='-'){//先对符号进行处理,后面就可以进行统一化。
        temp[cnt++]='-';
        i++;    
    } 

    for(;i<strlen(a);i++){//
        if(a[i]>='0'&&a[i]<='9')
            temp[cnt++]=a[i];
        else
            break;
    }
    temp[cnt]=0;//每取出一次数,就把数组最后一位置为字符串结束标志 
    sum[sum_cnt++]=atoi(temp);
    i--;   //跳出函数之后还是for循环,这可能就会导致直接跳两个字符,所以缩减一下 
}
int main(){
    cin>>a;
    sum_cnt=0;//记录有多少个整数 
    for(i=0;i<strlen(a);i++){
        if(a[i]=='-'&&a[i+1]>='0'&&a[i+1]<='9')//如果该数是负数 
            qushu();
        else if(a[i]>='0'&&a[i]<='9')//如果该数是正数 
                qushu();
        //这两个条件判断应该是非此即彼的关系。所以我们最好用else if进行连接 
    }
    int ans=0;
    for(int i=0;i<sum_cnt;i++)
        ans+=sum[i];
    cout<<sum_cnt<<" "<<ans<<endl;
    return 0;
} 

方法三:
来自半墨生烟的写法
利用i=i+j来更新指针,我觉得还蛮巧妙的。

#include<stdio.h>
#include<string.h>
int main()
{
    int i,j,sum=0,temp=0,len,t=0,flag=1;
    char a[1000];
    gets(a);
    len=strlen(a); 
    for(i=0;i<len;i++)
    {
        if(a[i]=='-'&&a[i+1]>='0'&&a[i+1]<='9')//如果为负数 
        {
            temp=0;
            for(j=1;a[i+j]>='0'&&a[i+j]<='9';j++)
                temp=temp*10+a[i+j]-'0';//临时存一个数 
            i=i+j;
            sum-=temp;
            t++;
        }
        else if(a[i]>='0'&&a[i]<='9')//如果为正数 
        {
            temp=0;
            for(j=0;a[i+j]>='0'&&a[i+j]<='9';j++)
                temp=temp*10+a[i+j]-'0';
            i=i+j;
            sum=sum+temp;
            t++;
        }
    }   
    printf("%d %d\n",t,sum);    
    return 0;
}

给定一个数字矩阵,如果上下左右数值相同,则表示是一个连通的区域。求矩阵中连通块的数量。输入:先是矩阵的行数和列数接着是矩阵输出:连通块的数量
例子
5 6
4 4 4 4 4 4
4 2 3 3 1 4
4 2 2 3 1 4
4 2 3 3 1 4
4 4 4 4 4 4
输出
4
说明所有4能连起来,还有2 3 1,都有各自能连通块。
思路:
这道题有很明显的BFS倾向,然后我就用BFS做了。。。
1、设置一个判断模块儿,(BFS最恶心的一个地方就是,它乱走,很有可能就会越界,或者直接走你走过的地方。)所以你需要设置一个判断模块儿,看自己是否走出地图的范围了,或者看一下你是不是走的是之前已经走过的路。而且这道题有个特点就是,只有两个字符相同了,你才能到达,他们之间才有路。
2、宽搜模块儿,实现一个点到它上下左右四个位置的遍历,对每一个位置进行判断。若判断模块儿为真,就加入队列,若为假,就说明该位置不可用。
宽搜流程:

  • 先把第一个点放入队列(这个点是我们宽搜的起点),并标记为访问过了。
  • 进入一个循环,条件为队列不空。这个是告诉我们只要你还有走路的可能,你就要一直走下去。
  • 每次循环取出队头,然后出队,标记为访问过。
  • 对取出的队头进行上下左右四个位置的尝试,每次尝试都判断一下是否能够满足判断模块儿,满足就入队,不满足就continue

3、我们要判断的是连通性。那我们要知道一点,需要一次BFS就能访问到所有节点的图一定是一个连通。需要两次才能访问完的一定是两个连通。我们利用这个性质写一个判断。如果BFS后还有没被访问过的点,那么连通的数量就+1.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<queue>
#include<iostream>
#define MAX 150
using namespace std; 
struct N{
    int x,y;
}now,tmp;
queue<N>q;
int map[MAX][MAX],n,m;
int X[4] = {0,0,1,-1};  
int Y[4] = {1,-1,0,0};   
bool visit[MAX][MAX];
bool judge(int x,int y,int value){//判断下一层的点是否符合规范 
    if(x>n||y>m||x<0||y<0)//越界不合法 
        return false;
    else if(visit[x][y])//访问过不合法    
        return false;
    else if(map[x][y]==value)//存储的值相同代表术语同一个区域 
        return true;
    else
        return false; 
}
void BFS(int x,int y,int value){
    int newx, newy;
    tmp.x=x;tmp.y=y;
    q.push(tmp);
    visit[tmp.x][tmp.y]=true;//标记为已经访问过 
    while(!q.empty()){
        now =q.front();
        q.pop();//从队头中取出元素。 
        for(int i=0;i<4;i++){
            newx = now.x + X[i];  
            newy = now.y + Y[i];  
            if(judge(newx,newy,map[now.x][now.y])){
            //进行比对,看是否是连通的。 
            //传给judge的是now节点的值,我们要得到的是now节点和temp节点比对之后的结果。
                tmp.x=newx;tmp.y=newy;
                q.push(tmp);
                visit[tmp.x][tmp.y]=true;
            }   
        }
    } 
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++)//开始创建图 
        for(int j=0;j<m;j++)
            cin>>map[i][j];
    int ans=0;
    memset(visit,false,sizeof(visit));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++){
            if(!visit[i][j]){//如果该节点还没有被访问过,就说明是一个新的连通区 
                ans++;
                BFS(i,j,map[i][j]); 
            } 
        }
    cout<<ans<<endl;
}

写法二:
思路是一样的,不过中间有一点点的写法上的不同。Update 0325

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<fstream>
#include<queue>
#define MAX 1010
using namespace std; 
int X[4]={0,0,1,-1},Y[4]={1,-1,0,0};
char map[MAX][MAX];
int n,m;
bool visit[MAX][MAX];
struct loc{
    int x;
    int y;
    char value;
}now,temp;
bool judge(int x,int y,char value){//value标记现在表示通路的字符 
    if(x>=n||y>=m||x<0||y<0)//越界 
        return false;
    if(visit[x][y])//如果已经访问过了
        return false;
    if(map[x][y]==value)//如果该位置的值也是通路上的值
        return true;
    return false; 
} 
void BFS(int x,int y,char value){
    now.x=x;now.y=y;
    now.value=value;
    queue<loc>q;
    q.push(now);
    visit[x][y]=true;
    while(!q.empty()){
        now=q.front();
        q.pop();
        for(int i=0;i<4;i++){
            temp.x=now.x+X[i];
            temp.y=now.y+Y[i];
            temp.value=map[temp.x][temp.y];
            if(judge(temp.x,temp.y,now.value)){
                q.push(temp);
                visit[temp.x][temp.y]=true;
            }
        }
    }
}
int main(){
    int ans=0;
    cin>>n>>m;
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            cin>>map[i][j];
    memset(visit,false,sizeof(visit));
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(!visit[i][j]){//如果还没被访问过,就说明肯定还有连通块儿 
                ans++;
                BFS(i,j,map[i][j]);                 
            }
    cout<<ans<<endl;
    return 0;
}

做法三:DFS
感觉最近几年的试题明显有很强的深搜倾向,大部分题都是和深搜相关的
代码如下:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#define N 101
using namespace std;
bool visit[N][N];//标记是否访问过该节点 
int DFS_COUNT;//记录有多少个连通分量 
int X[4]={0,0,1,-1},Y[4]={1,-1,0,00};//坐标转移数组 
int n,m;//输入图的大小 
char map[N][N];//用来存储图 
bool judge(int x,int y,char value){
    if(x>=n||x<0||y>=m||y<0)//如果越界就返回false 
        return false;
    if(visit[x][y])//如果访问过 
        return false;
    if(map[x][y]==value)//如果字符相同才表示这一条是通路 
        return true;
    return false; 
}
void dfs(int x,int y){
    visit[x][y]=true;
    for(int i=0;i<4;i++ ){//进行图的上下左右的遍历 
        int newx=x+X[i];
        int newy=y+Y[i];
        if(judge(newx,newy,map[x][y]))//如果该位置满足条件就递归 
            dfs(newx,newy);
    }       
}
void DFS(){
    memset(visit,false,sizeof(visit));//初始化访问数组 
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)//对整个图进行遍历 
            if(!visit[i][j]){               
                DFS_COUNT++;
                dfs(i,j);       
            }
}

int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++)//存储图 
        for(int j=0;j<m;j++)
            cin>>map[i][j]; 
    DFS();//进行深搜 
    cout<<DFS_COUNT<<endl;//输出连通个数
    return 0;
}

这道题如果稍微扩展下的话,可以和今年的初试题目一样,让你去判断环,判环的话,其实还是蛮难的,至今没有什么好的思路,对于上面这道题,我们能看到一个回路,就那个全是“4”的圈儿,哪个大佬说一下怎么判断出有这个环

评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值