1. 程式人生 > >杭電15年筆試真題詳解

杭電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”的圈兒,哪個大佬說一下怎麼判斷出有這個環