HRBU 2021年暑期训练阶段二Day1

目录

A - Breadth First Search

题目链接:https://vjudge.net/contest/451581#problem/A

图示

 B - Depth First Search

题目链接:https://vjudge.net/contest/451581#problem/B

图示

C - 非常可乐

题目链接:https://vjudge.net/contest/451581#problem/C

 D - Amazing Mazes

题目链接:https://vjudge.net/contest/451581#problem/D

 E - A计划

题目链接:https://vjudge.net/contest/451581#problem/E

F - Oil Deposits

题目链接:https://vjudge.net/contest/451581#problem/F

G - DNA sequence

题目链接:https://vjudge.net/contest/451581#problem/G


A - Breadth First Search

题目链接:HRBU 2021年暑期训练阶段二Day1 - Virtual Judge

题意:要求你运用广度优先搜索算法来求出,每个顶点到达根位置(顶点1)的最短距离

做法:BFS(广度优先搜索)简单来说就是,在遍历某一个数据的相邻边时,我先把这个边的所有相邻边遍历结束后,在去遍历下一个点

图示

第一步:先遍历1这个根节点的第一个相邻点2

第二步:再遍历1这个根节点的第二个相邻点4

第三步:根节点1的相邻点遍历结束,去遍历2这个节点,发现这个点的所有相邻节点都已经遍历过了所以直接去遍历4这个节点,发现只剩下一个相邻节点3还没有遍历,所以遍历3这个节点,随后遍历结束,输出结果。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include<fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=6;
int mp[maxn][maxn];
bool vis[maxn][maxn];
int sx,sy,ex,ey;
int t,u,n,x;
int dir[4][2]= {{0,1},{1,0},{0,-1},{-1,0}};
int a[110][110],s[110];

void bfs(int b)
{
    memset(s,-1,sizeof(s));
    queue<int> Q;
    Q.push(b);
    s[b]=0;
    while(!Q.empty())
    {
        int now=Q.front();
        //cout<<"now:"<<now<<endl;
        Q.pop();
        //int cnt=0;
        //cout<<"cnt:"<<cnt<<endl;
        for(int i=1; i<=t; i++)
        {
            if(s[i]!=-1)
                continue;
            if(a[now][i]==1)
                Q.push(i),s[i]=s[now]+1;//cnt++;
        }
        //cout<<"cnt:"<<cnt<<endl;
    }
}

int main()
{
    cin>>t;
    for(int j=1; j<=t; j++)
    {
        cin>>u>>n;
        for(int i=1; i<=n; i++)
            cin>>x,a[u][x]=1;
        /*for(int i=1; i<=t; i++)
        {
            for(int j=1; j<=4; j++)
                cout<<a[i][j]<<" ";
            cout<<endl;
        }*/
    }
    bfs(1);
    /*for(int i=1;i<=t;i++)
        cout<<s[i]<<endl;*/
    for(int i=1; i<=t; i++)
        cout<<i<<" "<<s[i]<<endl;
    return 0;
}

 B - Depth First Search

题目链接:HRBU 2021年暑期训练阶段二Day1 - Virtual Judge

题意:要求运用深度优先搜索遍历算法求出,从根节点出发到所有顶点遍历结束再回到根节点,所有点的遍历顺序

做法:DFS(深度优先搜索)遍历某个顶点时,先将这个顶点能够遍历最长的边遍历结束,之后再回溯到起始位置,进行下一个顶点的遍历

图示

第一步:由1点出发到2,再由2到3,从3再出发到5,接着由5继续到6,

第二步:发现到6之后没有其余的相邻节点了,所以开始回溯,由6开始回头,到5,到3,同时发现,到3之后在2这个点还有一个4没有遍历过,于是先遍历4然后再次没有了相邻节点,继续回溯,一直回溯到初始点1

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include<fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=6;
int mp[maxn][maxn];
int sx,sy,ex,ey;
int n,u,k,x,cnt;
int dir[4][2]= {{0,1},{1,0},{0,-1},{-1,0}};
int a[110][110];
bool vis[110];
struct Node
{
    int be;
    int en;
}s[110];

void dfs(int b)
{
    s[b].be=cnt++;
    for(int i=1;i<=n;i++)
    {
        if(a[b][i]==1&&!s[i].be)
            dfs(i);
    }
    s[b].en=cnt++;
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>u>>k;
        for(int j=1;j<=k;j++)
        {
            cin>>x;
            a[i][x]=1;
        }
    }
    cnt=1;
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++)
        s[i].be=s[i].en=0;
    for(int i=1;i<=n;i++)
    {
        if(!s[i].be)
            dfs(i);
    }
    for(int i=1;i<=n;i++)
        cout<<i<<" "<<s[i].be<<" "<<s[i].en<<endl;
    return 0;
}

C - 非常可乐

题目链接:HRBU 2021年暑期训练阶段二Day1 - Virtual Judge

题意:中文题面,理解不了自己的问题

做法:刚刚开始s中存放着所有的数据,n,m都是空的,要平分的过程中,当我们能做到把三个容器中一个倒空,另外两个则是相同的数据时,不就满足了我们要平分的条件了吗,其次如果一开始可乐的含量数就是奇数,这说明无论我们怎么去分,都是不可能分出相等的结果的,所以我们直接判断退出就行。3个杯子一共有3!=6次倒杯子的方法,所以我们只要bfs遍历这六个方法就行了

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define N 100+5
using namespace std;

struct node{
    int a,b,s,t;
}cole[N],st;

int a,b,s;
int vis[N][N];
int bfs()
{
    queue<node> q;
    memset(vis,0,sizeof(vis));
    st.a=0; st.b=0; st.s=s; st.t=0;
    q.push(st);
    vis[a][b]=1;
    while(!q.empty())
    {
        node u=q.front(),v;
        if(u.a==s/2 && u.s==s/2)
            return u.t;
        if(u.s && u.a!=a)   //s->a
        {
            int c=a-u.a;
            if(u.s>=c) v.a=a,v.s=u.s-c;
            else v.a=u.a+u.s,v.s=0;
            v.b=u.b; v.t=u.t+1;
            if(!vis[v.a][v.b])
            {
                q.push(v);
                vis[v.a][v.b]=1;
            }
        }
        if(u.s && u.b!=b)
        {
            int c=b-u.b;
            if(u.s>=c) v.b=b,v.s=u.s-c;
            else v.b=u.b+u.s,v.s=0;
            v.a=u.a; v.t=u.t+1;
            if(!vis[v.a][v.b])
            {
                q.push(v);
                vis[v.a][v.b]=1;
            }
        }
        if(u.a && u.s!=s)
        {
            int c=s-u.s;
            if(u.a>=c) v.s=s,v.a=u.a-c;
            else v.s=u.s+u.a,v.a=0;
            v.b=u.b; v.t=u.t+1;
            if(!vis[v.a][v.b])
            {
                q.push(v);
                vis[v.a][v.b]=1;
            }
        }
        if(u.a && u.b!=b)
        {
            int c=b-u.b;
            if(u.a>=c) v.b=b,v.a=u.a-c;
            else v.b=u.b+u.a,v.a=0;
            v.s=u.s; v.t=u.t+1;
            if(!vis[v.a][v.b])
            {
                q.push(v);
                vis[v.a][v.b]=1;
            }
        }
        if(u.b && u.a!=a)
        {
            int c=a-u.a;
            if(u.b>=c) v.a=a,v.b=u.b-c;
            else v.a=u.a+u.b,v.b=0;
            v.s=u.s; v.t=u.t+1;
            if(!vis[v.a][v.b])
            {
                q.push(v);
                vis[v.a][v.b]=1;
            }
        }
        if(u.b && u.s!=s)
        {
            int c=s-u.s;
            if(u.b>=c) v.s=s,v.b=u.b-c;
            else v.s=u.s+u.b,v.b=0;
            v.a=u.a; v.t=u.t+1;
            if(!vis[v.a][v.b])
            {
                q.push(v);
                vis[v.a][v.b]=1;
            }
        }
        q.pop();
    }
    return 0;
}
int main()
{
    while(scanf("%d%d%d",&s,&a,&b),s||a||b)
    {
        if(s%2)
        {
            puts("NO");
            continue;
        }
        if(a<b) swap(a,b);
        int ans=bfs();
        if(ans) printf("%d\n",ans);
        else puts("NO");
    }
    return 0;
}

 D - Amazing Mazes

题目链接:HRBU 2021年暑期训练阶段二Day1 - Virtual Judge

题意:需要从一个迷宫的右上角走到左下角,要是走不了输出0,否则的话输出最短的步数

做法:题目言简意赅,但是最大最大的难点就是在于迷宫的搭建上这个迷宫并不是我们常规的那种一个一部的迷宫,这个迷宫相当于一种上帝视角看到的三维迷宫,因为该迷宫的墙面是立体的。因此本题的重难点并不是在于该怎么去走迷宫而是如何搭建迷宫。

首先我们要明确,这个迷宫最外围一圈是无法行走的也就是下面图示的一种情况

这表示这我们搭建的这个迷宫矩阵的最外围一圈全部都是1(表示墙壁),因此我们在矩阵初始化时将边界全部初始化为1,关于起点和终点,因为我们搭建的这个矩阵既表示墙壁也表示房间,所以0,1以及右下角结点是0是1无所谓的,这并不会影响到我们迷宫的遍历

其次,就是题目中奇偶行输入代表的意思,奇数行代表的同一行内房间的位置以及每个房间之间墙的存在情况,偶数行则代表上下方向的房间之间墙的情况;这是我们在矩阵初始化输入时就在考虑的问题,把奇数位当成房间,偶数位当成房间之间的墙,因为这个迷宫的特殊性,所以每一次遍历其实我们都是移动两个的距离,因为人是不能在墙壁中行走的。因此墙的位置存放什么数据一点都不影响最后的结果,再来一个BFS的板子遍历,最后注意一点遍历时需要特判你要到达的点的中间位置是能通行的,不然两点间根本不连通,怎么可能到达呢?

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include<fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=70;
int n,m,ex,ey;
int dir[4][2]= {{0,2},{2,0},{0,-2},{-2,0}};
int mp[maxn][maxn];
int dis[maxn][maxn];
struct Node
{
    int x,y;
};

void make(int n,int m)
{
    memset(mp,0,sizeof(mp));
    for(int i=0;i<=2*n;i++)
    {
        if(i==0||i==2*n)
        {
            for(int j=0;j<=2*m;j++)
                mp[i][j]=1;
        }
        else
            mp[i][0]=mp[i][2*m]=1;
    }
    for(int i=1;i<=2*n-1;i++)
    {
        if(i%2==1)
        {
            for(int j=0;j<m-1;j++)
                cin>>mp[i][2*j+2];
        }
        else
        {
            for(int j=0;j<m;j++)
                cin>>mp[i][2*j+1];
        }
    }
    ex=2*n-1;
    ey=2*m-1;
}

int bfs()
{
    queue<Node> Q;
    memset(dis,-1,sizeof(dis));
    Q.push((Node){1,1});
    dis[1][1]=0;
    while(!Q.empty())
    {
        Node now=Q.front();
        Q.pop();
        if(now.x==ex&&now.y==ey)
            break;
        for(int i=0;i<4;i++)
        {
            int xx=now.x+dir[i][0];
            int yy=now.y+dir[i][1];
            if(xx>=1&&xx<=2*n&&yy>=1&&yy<2*m&&mp[(xx+now.x)/2][(yy+now.y)/2]==0&&mp[xx][yy]==0&&dis[xx][yy]==-1)
            {
                Q.push((Node){xx,yy});
                dis[xx][yy]=dis[now.x][now.y]+1;
            }
        }
    }
    return dis[ex][ey]+1;
}

int main()
{
    while(cin>>m>>n&&n&&m)
    {
        make(n,m);
        int ans=bfs();
        cout<<ans<<endl;
    }
    return 0;
}

 E - A计划

题目链接:HRBU 2021年暑期训练阶段二Day1 - Virtual Judge

做法:三维的BFS遍历,唯一需要注意的一点就是,当踩到了传送位置时,是不计算步数的,直接送到下一层

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include<fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
# define inf 0x3f3f3f3f
# define maxn 15
int n,m,t;
char mp[2][maxn][maxn];
int dir[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
struct Node
{
    int x,y,z,Tim;
};

int bfs()
{
    queue<Node> Q;
    Q.push((Node){0,1,1,0});
    while(!Q.empty())
    {
        Node now=Q.front();
        Q.pop();
        if(mp[now.x][now.y][now.z]=='P')
            return 1;
        else if(mp[now.x][now.y][now.z]=='*')
            continue;
        mp[now.x][now.y][now.z]='*';
        for(int i=0;i<4;i++)
        {
            int xx=now.x;
            int yy=now.y+dir[i][0];
            int zz=now.z+dir[i][1];
            if(mp[xx][yy][zz]=='*'||now.Tim+1>t)
                continue;
            if(mp[xx][yy][zz]=='#')
            {
                mp[xx][yy][zz]='*';
                xx=1-xx;
                if(mp[xx][yy][zz]=='#'||mp[xx][yy][zz]=='*')
                {
                    mp[xx][yy][zz]=mp[1-xx][yy][zz]='*';
                    continue;
                }
            }
            Q.push((Node){xx,yy,zz,now.Tim+1});
        }
    }
    return 0;
}

/*int bfs()
{
    Node n1;

    n1.x = 0;
    n1.y = 1;
    n1.z = 1;
    n1.Tim = 0;

    queue<Node> q;
    q.push(n1);

    while (!q.empty())
    {
        Node n2 = q.front();
        q.pop();

        if (mp[n2.x][n2.y][n2.z] == 'P')
            return 1;
        else if (mp[n2.x][n2.y][n2.z] == '*')
            continue;

        mp[n2.x][n2.y][n2.z] = '*';

        for (int i = 0; i < 4; i++) {
            Node n3;

            n3.x = n2.x;
            n3.y = n2.y + dir[i][0];
            n3.z = n2.z + dir[i][1];
            n3.Tim = n2.Tim + 1;

            if (mp[n3.x][n3.y][n3.z] == '*' || n3.Tim > t)
                continue;
            else if (mp[n3.x][n3.y][n3.z] == '#') {
                mp[n3.x][n3.y][n3.z] = '*';
                n3.x = 1 - n3.x;
                if (mp[n3.x][n3.y][n3.z] == '#' || mp[n3.x][n3.y][n3.z] == '*') {
                    mp[n3.x][n3.y][n3.z] = mp[1 - n3.x][n3.y][n3.z] = '*';
                    continue;
                }
            }

            q.push(n3);
        }
    }
    return 0;
}*/

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>m>>n>>t;
        memset(mp,'*',sizeof(mp));
        for(int i=0;i<2;i++)
        {
            for(int j=1;j<=m;j++)
            {
                for(int k=1;k<=n;k++)
                    cin>>mp[i][j][k];
            }
        }
        int ans=bfs();
        if(ans)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

F - Oil Deposits

题目链接:HRBU 2021年暑期训练阶段二Day1 - Virtual Judge

题意:给定一块油田的俯视图,一个@代表一块油田,但是若这个油田的八个方向里有任意一个方向存在另一个油田的话,这两块油田算是一块油田,也就是说这是一个连通块,问你有多少个连通块。

做法:简单的深搜遍历就好了,把每一次遍历的点都直接变成 * 防止对后续深搜的回溯产生影响,需要注意一个方向,遍历的方向是8个,而不是常规的4个

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include<fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int maxn=110;
int n,m,cnt=0,flag;
int dir[8][2]= {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
char mp[maxn][maxn];

int dfs(int x,int y)
{
    if(mp[x][y]=='*')
        return flag;
    mp[x][y]='*';
    flag=1;
    for(int i=0;i<8;i++)
    {
        int xx=x+dir[i][0];
        int yy=y+dir[i][1];
        if(xx>=1&&xx<=n&&yy>=1&&yy<=m)
            dfs(xx,yy);
    }
    return flag;
}

int main()
{
    while(cin>>n>>m)
    {
        cnt=0;
        if(n==0&&m==0)
            break;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                cin>>mp[i][j];
        }
        //cout<<1<<endl;
        for(int i=1;i<=n;i++)
        {
            //cout<<"i:"<<i<<endl;
            for(int j=1;j<=m;j++)
            {
                flag=0;
                if(dfs(i,j))
                    cnt++;
            }
            //cout<<"i+1:"<<i+1<<endl;
        }
        //cout<<2<<endl;
        cout<<cnt<<endl;
    }
    return 0;
}

G - DNA sequence

题目链接:HRBU 2021年暑期训练阶段二Day1 - Virtual Judge

题意:给定几个字符串,要求求出一个最短的序列,做到输入的每一个序列都是这个序列的子序列,输出长度

做法:全新的知识,IDA*(迭代深搜索)和普通的深搜多了一个限制条件,规定的一个最小的长度限制,当你的长度超过限制时,就不在遍历直接返回,然后将限制的范围加大,一直到满足所有的长度为止时,这时答案就是一个最小值

借鉴博客:hdu 1560 DNA sequence(迭代加深搜索)_TommyTT的博客-CSDN博客(没有解释IDA*但是通过对题目思路的解析其实也差不多)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<cstdlib>
#include<fstream>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
# define inf 0x3f3f3f3f
# define maxn 10
int len[maxn];
char a[maxn][maxn];
int n;
int  ans,deep;
int point[maxn];
int com[4]= {'A','G','C','T'};
void dfs(int t1,int temp[])
{
    if(t1>deep)return ;
    int maxx=0;
    for(int i=0; i<n; i++)
    {
        int t=len[i]-temp[i];
        maxx=max(t,maxx);
    }
    if(maxx==0)
    {
        ans=t1;
        return ;
    }
    if(maxx+t1>deep)return ;
    for(int i=0; i<4; i++)
    {
        int flag=0;
        int t[10];
        for(int j=0; j<n; j++)
        {
            if(a[j][temp[j]]==com[i])
            {
                flag=1;
                t[j]=temp[j]+1;
            }
            else t[j]=temp[j];
        }
        if(flag==1)
        {
            dfs(t1+1,t);
        }
        if(ans!=-1)break;
    }
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        deep=0;
        cin>>n;
        int maxx=-1;
        for(int i=0; i<n; i++)
        {
            cin>>a[i];
            int l=strlen(a[i]);
            len[i]=l;
            if(maxx<l)maxx=l;
        }
        ans=-1;
        while(1)
        {
            dfs(0,point);
            if(ans!=-1)break;
            deep++;
        }
        cout<<ans<<endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值