2018暑假集训楼下第八场(深广搜)

A - Red and Black(POJ 1979)
题意:
一个被方形瓷砖覆盖的矩形房间,瓷砖分为红黑两种颜色。一个人站在一块黑色的瓷砖上,他可以移动到相邻(上,下,左,右)的瓷砖上。但是他不可以移动到红色的瓷砖上。写一个程序计算有多少块黑色的瓷砖这个人可以到达.
包括多组输入,两个零代表输入结束。
输入:’.’代表一块黑色的瓷砖
’#‘代表红色的瓷砖
’@‘代表这个人所在的位置
题解:
根据题意,要找到搜有的可以到达的瓷砖,所有选择深度优先搜索。

#include <stdio.h>
#include<iostream>
#include<algorithm>
#include <string.h>
using namespace std;
const int N=25;
char tile[N][N];
int d[4][2]={{-1,0},{0,-1},{1,0},{0,1}};
int v[N][N];
int w,h,coun;
int judge(int x,int y)
{
    return 0<=x&&x<h&&0<=y&&y<w&&tile[x][y]=='.';
}
void DFS(int x,int y)
{
    int xx,yy;
    tile[x][y]='#';
    for (int i=0; i<4; i++)
    {
        xx=x+d[i][0];
        yy=y+d[i][1];
        if(judge(xx,yy))
        {
            coun++;
            DFS(xx,yy);
        }
    }
}
int main()
{
    while (~scanf("%d %d",&w,&h)&&w&&h)
    {
        getchar();
        int xs=0,ys=0;
        for (int i=0; i<h; i++)
        {
            for (int j=0; j<w; j++)
            {
                scanf("%c",&tile[i][j]);
                if (tile[i][j]=='@')
                {
                    xs=i;
                    ys=j;
                }
            }
            getchar();
        }
        coun=1;
        DFS(xs,ys);
        printf("%d\n",coun);
    }
    return 0;
}

B - Lake Counting(POJ 2386)
题意:
因为下雨,农田里积了很多水。一块N×M个小方块的的矩形农田,每个方块分别由‘W’和’.‘组成,W’代表积水,’.‘代表干燥的陆地。农夫现在想知道在他的农田里有多少块水池。如果两个小水池是相邻的则被看成一个水池,一个水池有八个方向。
题解:
深度优先搜寻,遍历每个点是否是W,如果是W,则从这个点开始进行八个方向的深度优先搜寻,被访问过的小水池W标记为‘.’,以后不会再被访问直到把相邻的水池都访问完毕结束搜索,ans++;如果图中还有没被访问的水池,再次进行深搜。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int N=120;
char adj[N][N];
int coun;
int w,h;
int d[8][2]= {{-1,0},{-1,-1},{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1}};
//判断下标是否越界
int judge(int x,int y)
{
    return (0<=x&&x<w&&0<=y&&y<h);
}
void DFS(int x,int y)
{
    int xx,yy;
    adj[y][x]='.';//用'.'标记,此块'W'已被访问过
    for (int i=0; i<8; i++)
    {
        xx=x+d[i][0];
        yy=y+d[i][1];
        if (judge(xx,yy)&&adj[yy][xx]=='W')
        {
            DFS(xx,yy);
        }
    }
}
int main()
{
    int ans;
    while (~scanf("%d %d",&h,&w))
    {
        if (h==0)
            break;
        getchar();
        for (int i=0; i<h; i++)
        {
            scanf("%s",adj[i]);
        }
        ans=0;
        for (int i=0; i<h; i++)
        {
            for (int j=0; j<w; j++)
            {
                if (adj[i][j]=='W')
                {
                    DFS(j,i);
                    ans++;//访问完一块连接的水,ans++
                }
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

C-变形课(HDU 1181)
题意: 中文题意不解释
题解: 为了方便搜索把每个单词的第一个字母和最后一个单词存进数组里,然后进行深搜就可以了。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
char s[50];
char c[1000][2];//用来存每个单词的开头和结尾
int v[1000];
int flag;
void dfs(int i,int n)
{
    if (c[i][1]=='m')
    {
        flag=1;
        return ;
    }
    for (int j=0; j<n; j++)
    {
        if (v[j]==0&&c[j][0]==c[i][1])
        {
            v[ j ]=1;
            dfs(j,n);
            //v[j]=0;不用回溯,因为当你查到某个单词结束时就说明这条线已经走不通了,所以说这个单词就没必要再查了
        }
    }
}
int main()
{
    int i=0,j;
    while (~scanf("%s",s))
    {
        flag=0;
        memset(c,0,sizeof(c));
        c[0][0]=s[0];
        c[0][1]=s[strlen(s)-1];
        i=1;
        while (~scanf("%s",s))
        {
            if (s[0]=='0')
                break;
            c[ i ][0]=s[0];
            c[ i ][1]=s[strlen(s)-1];
            i++;
        }
        for ( j=0; j<i; j++)
        {
            if (c[ j ][0]=='b')
            {
                dfs(j,i);
            }
        }
        if (flag)
            printf("Yes.\n");
        else
            printf("No.\n");
    }
    return 0;
}

D-Rescue(HDU 1242)
题意: 天使被抓进了监狱,监狱是N*M的矩形,监狱里有WALLs, ROADs, and GUARDs 。天使的朋友想救天使出来,想救天使出来就要到达天使被关的监狱的房间。路途中可能遇见GUARDs,他们要杀死GUARDs,在监狱里天使的朋友可以上,下,左,右移动,每移动一次花费的时间是一分钟,杀死守卫花费的时间也是一分钟,问要救出天使所花费的最短时间是多久。
“.” 代表路,,”a” 代表天使, “r” 代表每个人天使的朋友,”x”代表守卫,”#”代表墙。
题解: 根据题意要找最短时间,所以用广度优先搜索。注意使用优先队列,应为杀死守卫要多花费一分钟。

//代码
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=250;
int w,h;
int xs,ys;  //起始位置
int flag;   //是否找到angel
char moli[N][N];
int v[N][N];
int d[][2]= {{0,1},{-1,0},{0,-1},{1,0}};    //方向
struct P
{
    int x,y,step;
    friend bool operator < (P a,P b)
    {
        return a.step>b.step;
    }
} ;
//struct cmp
//{
//    bool operator () (P a,P b)
//    {
//        return a.step>b.step;
//    }
//};
//判断是否超出城堡界限
int judge(int x,int y)
{
    if( x<0 || y<0 || x>h || y>w )
        return 0;
    if(v[x][y])
        return 0;
    if( moli[x][y]=='#' )
        return 0;
    return 1;
}
/*广度优先搜素是利用队列实现*/
void BFS()
{
    P a,b;
    flag=0;
    memset(v,0,sizeof v);
    v[xs][ys]=1;
    a.x=xs;
    a.y=ys;
    a.step=0;
    priority_queue<P>Q;
    Q.push(a);
    while (!Q.empty())
    {
        a=Q.top();
        Q.pop();
        /*找到angel输出时间*/
        if (moli[a.x][a.y]=='a')
        {
            printf("%d\n",a.step);
            flag=1;
            break;
        }
        /*判断一个格子的上,下,左,右是否可走*/
        for (int i=0; i<4; i++)
        {
            b.x=a.x+d[i][0];
            b.y=a.y+d[i][1];
            if (judge(b.x,b.y))
            {
                if (moli[b.x][b.y]=='x')
                    b.step=a.step+2;//这里就是为什么要用优先队列
                else
                    b.step=a.step+1;
                v[b.x][b.y]=1;
                Q.push(b);
            }
        }
    }
}
int main()
{
    while (~scanf("%d %d",&h,&w))
    {
        for (int i=0; i<h; i++)
        {
            for (int j=0; j<w; j++)
            {
                scanf("%c",&moli[i][j]);
                if (moli[i][j]=='r')
                    xs=i,ys=j;
            }
            getchar();
        }
        BFS();
        if (!flag)
            printf("Poor ANGEL has to stay in the prison all his life.\n");
    }
    return 0;
}

E-Catch That Cow(POJ 3278)
题意:
John的一头牛跑了,Joh想马上抓住他。John在点n,奶牛在点k。n,k在同一条线上。John有两种移动方式:walking and teleporting。
Walking:可以从点x移动到点x-1或者x+1.
Teleporting:可以从点X移动到2*x。
奶牛是不动的。移动一次的需要一分钟,问John最短多久可以抓住奶牛。
题解:
根据题意要找最短时间,所以要用广度优先搜索。队列里存放的是John,每一步位置的坐标。要注意的一点是,虽然数据量是1e5 但是John可以移动到他2*x的位置。所以John可能会移动到2e5的位置,所以数组要开到2e5。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
const int N=2e5+7;
int v[N];//标记x是否已被走过
int coun[N];//记录走到x所用的时间
int n,k;
void bfs()
{
    queue<int > Q;
    int x;
    Q.push(n);
    v[n]=1;
    while (!Q.empty())
    {
        x=Q.front();
        Q.pop();
         if (x==k)
            break;
        if (x+1<=k&&!v[x+1])
        {
            Q.push(x+1);
            coun[ x+1 ]=coun[ x ]+1;
            v[x+1]=1;
        }
        if (x-1>=0&&!v[x-1])
        {
            Q.push(x-1);
            coun[ x-1 ]=coun[ x ]+1;
            v[x-1]=1;
        }
        if (x*2<2*k&&!v[x*2])
        {
            Q.push(x*2);
            coun[ x*2 ]=coun[ x ]+1;
            v[x*2]=1;
        }
    }
}
int main()
{
    while (~scanf("%d  %d",&n,&k))
    {
        memset(v,0,sizeof(v));
        memset(coun,0,sizeof(coun));
        bfs();
        printf("%d\n",coun[k]);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值