数据结构期末复习题集8~12

本文由zhc撰写

小测8 - 最短路径 实时评测
问题描述:
唐僧被妖怪关在迷宫中。孙悟空好不容易找到一张迷宫地图,并通过一个魔法门来到来到迷宫某个位置。假设迷宫是一个n * m的矩阵,它有两种地形,0表示平地,1表示沼泽,孙悟空只能停留在平地上。
孙悟空目前的位置在坐标(sx,sy)处,他可以向上下左右四个方向移动。
请你帮助孙悟空计算一下,迷宫中是否存在一条路从他所在位置(sx,sy)到达唐僧所在位置(tx,ty),如果有,请计算出最短的一条路径。

输入描述:
每个测试样例的第1行是2个正整数n (1≤n≤100),m (1≤m≤100),表示迷宫是n * m的矩阵。接下来的n行输入迷宫,每行有m个数字(0或者1),数字之间用一个空格间隔。
接下来的1行是4个整数sx,sy,tx,ty,1≤sx,tx≤n,1≤sy,ty≤m,表示孙悟空所在位置为第sx行第sy列,唐僧所在位置为第tx行第tx列。迷宫左上角编号是(1,1),右下角编号是(n, m)。
数据保证(sx,sy)格和(tx,ty)必定为平地,且孙悟空的初始位置(sx, sy)并不在唐僧所在格(tx, ty)。

输出描述:
输出孙悟空到达唐僧处所需经过的最短路径,如果不能到达,请输出“No”

输入样例1:
2 2
0 1
1 0
1 1 2 2

输出样例1:
No

输入样例2:
4 4
0 0 0 1
0 1 0 0
0 1 0 0
0 0 0 1
1 1 3 4

输出样例2:
5

#include <iostream>
#include<vector>
#include<cstring>
using namespace std;
int n,m;
int near[4][2]={0,1,0,-1,1,0,-1,0};
int d[101][101];
int best[101][101];
int vis[101][101];

void refresh(int x,int y){
    for(int i=0;i<4;++i){
        int x0=x+near[i][0];
        int y0=y+near[i][1];
        if(x0<1||x0>n||y0<1||y0>m) continue;
        if(d[x0][y0]==1&&best[x0][y0]>(best[x][y]+d[x0][y0])){
            best[x0][y0]=best[x][y]+d[x0][y0];
        }
    }
}

int main(){
    cin>>n>>m;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            int t;
            cin>>t;
            d[i][j]=1-t;
            best[i][j]=9999;
            vis[i][j]=0;
        }
    }
    int sx,sy,tx,ty;
    cin>>sx>>sy>>tx>>ty;
    if(sx==tx&&sy==ty){
        cout<<0;
        return 0;
    }
    best[sx][sy]=0;
    vis[sx][sy]=1;
    refresh(sx,sy);
    while(true){
        int min=9999;
        int x,y;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                if(d[i][j]==1&&vis[i][j]==0&&min>best[i][j]){
                    min=best[i][j];
                    x=i;
                    y=j;
                }
            }
        }
        if(min==9999) break;
        if(x==tx&&y==ty) break;
        vis[x][y]=1;
        refresh(x,y);
    }

    if(best[tx][ty]==9999) cout<<"No";
    else  cout<<best[tx][ty];
    return 0;
}

小测9 - 简单哈希 实时评测
题目描述
使用线性探测法(Linear Probing)可以解决哈希中的冲突问题,其基本思想是:设哈希函数为h(key) = d, 并且假定哈希的存储结构是循环数组, 则当冲突发生时, 继续探测d+1, d+2…, 直到冲突得到解决.
例如, 现有关键码集为 {47,7,29,11,16,92,22,8,3},设:哈希表表长为m=11;哈希函数为Hash(key)=key mod 11;采用线性探测法处理冲突。建哈希表如下:请输入图片描述

现在给定哈希函数为Hash(key)= key mod m,要求按照上述规则, 使用线性探测法处理冲突.要求建立起相应哈希表,并按要求打印。

输入描述
仅有一个测试用例, 第1行为整数n与m(1 <= n, m <= 10000), n代表key的总数, m代表哈希表的长度, 并且令哈希函数为: Hash(key) = key mod m.
接下来n行,每行一个整数,代表一个key。Key与key两两不相同 ( 0 <= key <= 10, 000)。

输出描述
输出建立好的hash表,比如下表
请输入图片描述

应输出
0#11
1#22
2#NULL
3#47
4#92
5#16
6#3
7#7
8#29
9#8
10#NULL

#include<iostream>
using namespace std;

int main(){
    int n,m;
    cin>>n>>m;
    int data[m];
    for(int i=0;i<m;++i) data[i]=-1;
    for(int i=0;i<n;++i){
        int num;
        cin>>num;
        int key=num%m;
        int k=0;
        while(data[(key+k)%m] !=-1) ++k;
        data[(key+k)%m]=num;
    }
    for(int i=0;i<m;++i){
        cout<<i<<"#";
        if(data[i]==-1) cout<<"NULL"<<endl;
        else cout<<data[i]<<endl;
    }
}

小测10 - 简单字符串匹配
题目描述
给定两个字符串s1和s2,要求判定s2是否能够被s1做循环移位(rotate)得到的字符串包含。说明:字符串s1和s2中不包含空格,每个字符串至少包含一个字符。
例如:给定S1= AABCD,S2=CDAA,则返回True;给定s1=ABCD,S2=ACBD,则返回False

输入描述
第一行为整数n(n<2,000,0),第2到n+1行为n个输入数据,每行包括两个字符串,字符串s1和字符串s2。字符串的长度不超过100。

输出描述
针对每个例子,如果s2能够被s1做循环移位得到的字符串包含,输出True,否则输出False;每个输出结果为独立的一行。

输入样例
2
AABCD CDAA
ABCD ACBD

输出样例
True
False

#include<iostream>
using namespace std;

int main(){
    int times;
    cin>>times;
    while(times-->0){
        string s1,s2;
        cin>>s1>>s2;
        bool ok=false;
        for(int i=0;i<s1.size();++i){
            if(s1[i]==s2[0]){
            ok=true;
            int k1=i;
            int k2=0;
            while(k2<s2.size()){
                if(s1[k1]!=s2[k2]){
                    ok=false;
                    break;
                }
                k1++;
                k1=k1%(s1.size());
                k2++;
            }
            if(ok) break;
            }
        }
        if(ok) cout<<"True"<<endl;
        else cout<<"False"<<endl;
    }
    return 0;
}

小测11 - 畅通工程 实时评测
2022-01-19 18:08
1000 ms
32 MB
李正鸿 (lizhh98@mail2.sysu.edu.cn)
题目描述
某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。
现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

输入描述
本题目包含多组数据,请处理到文件结束。
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。
接下来是M行道路信息。每一行有三个整数A,B,X(0<A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

输出描述
对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1.

输入样例
3 3
0 1 1
0 2 3
1 2 1
0 2
3 1
0 1 1
1 2

输出描述
2
-1

#include<iostream>
#include<cstring>
using namespace std;
#define int_max 2000000//int_max

int N;
int best[200];
int vist[200];
int d[200][200];

void refresh(int x){
    for(int i=0;i<N;++i){
        if(d[x][i]!=-1&&best[i]>(best[x]+d[x][i]))
        best[i]=best[x]+d[x][i];
    }
}

int main(){
    while(cin>>N){
        int M;
        cin>>M;
        //memset(vist,0,sizeof(vist));
        //memset(best,int_max,sizeof(best));
        memset(d,-1,sizeof(d));
        for(int i=0;i<N;++i){
            d[i][i]=0;
            vist[i]=0;    
            best[i]=int_max;
        }
        for(int i = 0; i <M ; ++i){
            int x,y,t;
            cin>>x>>y>>t;
            if(x!=y&&(d[x][y]==-1||t<d[x][y])){
                d[x][y]=t;
                d[y][x]=t;
            }
        }
        int start,end;
        cin>>start>>end;
        if(start==end){
            cout<<0<<endl;
            continue;
        }
        best[start]=0;
        vist[start]=1;
        refresh(start);
        while(true){
            int min=int_max;
            int closest;
            for(int i=0;i<N;++i){
                if(vist[i]==0&&min>best[i]){
                    min=best[i];
                    closest=i;
                }
            }
            if(min==int_max) break;
            if(closest==end) break;
            vist[closest]=1;
            refresh(closest);
        }
        if(best[end]==int_max) cout<<-1<<endl;
        else cout<<best[end]<<endl;
    }
    return 0;
}

小测12 - 飞盘高手
题目描述
杰克是美国某小镇有名的飞盘高手。他掷飞盘的时候有一个习惯,在一叠飞盘中,从第一个飞盘(即位于顶端的飞盘)开始,从上往下依次编号为1~N。当至少还有两个飞盘的时候,杰克通常会掷出一个飞盘,然后把新的第一个飞盘放到所有飞盘的最后。输入N,输出每次扔掉的飞盘,以及最后剩下的飞盘。

输入描述
第一行为一个整数t(0<t<20),表示测试用例个数。以下t行每行包含一个整数n(0<n<40),为一个测试用例的飞碟数。

输出描述
为每个测试用例单独输出一行,该行中依次输出每次掷出的飞盘编号以及最后剩下飞盘,每个飞盘后跟着一个空格。

输入样例
2
7
4

输出样例
1 3 5 7 4 2 6
1 3 2 4

#include<iostream>
#include<queue>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t-->0){
        int n;
        cin>>n;
        queue<int> Q;
        for(int i = 1; i<=n;++i) Q.push(i);
        for(int k=0;k<n;++k){
            cout<<Q.front()<<" ";
            Q.pop();
            Q.push(Q.front());
            Q.pop();
        }
        cout<<endl;
    }
}
支持 makedown语法