搜索专题

以DFS和BFS为主的复习。


  • DFS

题目1链接:http://hihocoder.com/problemset/problem/1310?sid=1348820

题意:和蓝桥杯省赛那题有点像。岛屿问题。题目求的是有多少个岛屿,多少个面积不同的岛屿,多少个形状不同的岛屿。

注意:这里形状相同指的是一个岛屿可以由另一个平移得到(不能旋转)

题解:

        求有多少不同岛屿==求连同块的数量,求有多少面积不同的岛屿顺手用map统计一下就行了

        关键在于求有多少形状不同的岛屿。我们对于一个点(x,y),可以把它哈希成x*(n-1)+y,当然这是从x,y都从1开始的情况。然后把一个联通块的哈希值加入vector,排个序。

        对比两个联通块形状是否相同,就是判断两个vector的size是否相同,以及每个元素对应差值是否相同。

bool isok(int i,int j)
{
    if(e[i].size()!=e[j].size())
        return false;
    int temp = e[i][0]-e[j][0];
    for(int k=1;k<e[i].size();k++)
    {
        if(temp!=e[i][k]-e[j][k])
            return false;
    }
    return true;
}

       思考点:如何求有多少个不同的。这时候的求法应该是,每加入一个元素,看其与之前的元素是否都不同,如果存在相同的,那么flag就是false,反之为true,结果+1.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 55;
#define eps 1e-8
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;

inline void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}

inline void print(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int n,m,ans1,ans2,ans3,tot;
char s[maxn][maxn];
bool vis[maxn][maxn];
int dir[4][2] = {1,0,-1,0,0,1,0,-1};
map<int,int> mp;
vector<int> e[maxn*10];

void dfs(int x,int y,int &tot)
{
    tot++;
    vis[x][y] = 1;
    e[ans1].push_back(x*m+y+1);
    for(int i=0;i<4;i++)
    {
        int newx = x+dir[i][0];
        int newy = y+dir[i][1];
        if(!vis[newx][newy]&&newx>=0&&newy>=0&&newx<n&&newy<m&&s[newx][newy]=='#')
        {
            dfs(newx,newy,tot);
        }
    }
}

bool isok(int i,int j)
{
    if(e[i].size()!=e[j].size())
        return false;
    int temp = e[i][0]-e[j][0];
    for(int k=1;k<e[i].size();k++)
    {
        if(temp!=e[i][k]-e[j][k])
            return false;
    }
    return true;
}

int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
        scanf("%s",s[i]);
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(s[i][j]=='#'&&vis[i][j]==0)
            {
                tot = 0;
                ans1++;
                dfs(i,j,tot);
                sort(e[ans1].begin(),e[ans1].end());
                mp[tot]++;
            }
        }
    }
    for(int i=1;i<=ans1;i++)
    {
        bool flag = 0;
        for(int j=1;j<i;j++)
        {
            if(isok(i,j))
                flag = 1;
        }
        if(!flag)
            ans3++;
    }
    cout<<ans1<<" "<<mp.size()<<" "<<ans3<<endl;
    return 0;
}

  • BFS

题目链接:http://hihocoder.com/problemset/problem/1092?sid=1348945

题意:有两个人从同一点出发,要找两个相邻的座位。问加起来的最短路。

题解:可以现在地图上面找用多少个位置符合条件,每遇到两个相邻的座位,就把他们分别加入bfs求最短路,如果两个最短路之和<ans,那么就更新结果。

#include <bits/stdc++.h>
using namespace std;

const int inf = 0x3f3f3f3f;
const int maxn = 105;
#define eps 1e-8
#define INIT(x) memset(x,0,sizeof(x))
typedef long long ll;

int n,m,sx,sy,ans=inf,temp_ans=inf;
char s[maxn][maxn];
int dir[4][2] = {1,0,0,1,0,-1,-1,0};
bool vis[maxn][maxn];

struct node{
    int x,y,step;
};

void bfs(int x,int y)
{
    INIT(vis);
    node a;
    a.x = sx;
    a.y = sy;
    a.step = 0;
    queue<node> q;
    while(!q.empty())
        q.pop();
    q.push(a);
    while(!q.empty())
    {
        node pre = q.front();
//        cout<<pre.x<<" "<<pre.y<<endl;
        q.pop();
        for(int i=0;i<4;i++)
        {
            int newx = pre.x + dir[i][0];
            int newy = pre.y + dir[i][1];
            if(!vis[newx][newy]&&newx>=0&&newx<n&&y>=0&&newy<m&&s[newx][newy]!='P'&&s[newx][newy]!='#')
            {
                if(s[newx][newy]=='S'&&(newx!=x||newy!=y))
                    continue;
                vis[newx][newy] = 1;
                node cnt;
                cnt.x = newx;
                cnt.y = newy;
                cnt.step = pre.step+1;
                if(newx==x&&newy==y) {
                    temp_ans = min(temp_ans,cnt.step);
                    return;
                }
                q.push(cnt);
            }
        }

    }
}

int main()
{
    cin>>n>>m;
    for(int i=0;i<n;i++)
        scanf("%s",s[i]);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            if(s[i][j]=='H')
            {
                sx = i;
                sy = j;
            }
//    cout<<sx<<" "<<sy<<endl;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            if(s[i][j]=='S')
            {
                bool flag = 0;
                int newx,newy;
                for(int k=0;k<4;k++)
                {
                    newx = i+dir[k][0];
                    newy = j+dir[k][1];
                    if(s[newx][newy]=='S')
                    {
                        flag = 1;
                        break;
                    }
                }
                if(flag)
                {
                    temp_ans = inf;
                    bfs(i,j);
                    int ans1 = temp_ans;
                    temp_ans = inf;
                    bfs(newx,newy);
                    int ans2 = temp_ans;
                    ans = min(ans,ans1+ans2);
                }
            }
        }
    }
    if(ans>=inf)
    {
        cout<<"Hi and Ho will not have lunch."<<endl;
        return 0;
    }
    cout<<ans<<endl;
    return 0;
}

注意点:最大只能设为0x3f3f3f3f,而不是2^31-1,因为可能ans1+ans2溢出,导致ans变小

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总想玩世不恭

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值