CSL的校园卡【牛客小白月赛7】【BFS+四维+状压】

题目链接

  题意:

有两个人,同时从起点出发,问他们要走多少时间才能走完所有点(两个人的合计)。

 

思路:

  这道题,我们如果是一条边的情况,那当然是简单的BFS,但是,对于两条边,我们得对BFS进行一下升华,对于这个BFS,我们得开一个四维+状压的数组,vis[i][x1][y1][x2][y2]:i是状压后的路径,表示走过这些点群,之后(x1, y1),(x2, y2)分别表示两个小人分别走到的点,然后每次走过的时候,就需要判断这个点能否能走,然后对该点的状态进行“异或(|)”处理。用一个队列去记录值的点,每次出队的时候判断是否这个出队的点已经遍历了所有的可走点,如果是的,就直接跳出子函数,因为,那必定是最先的那个点(BFS定理了)。

 

完整代码

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef long long ll;
const int maxN=4;
int dir[4][2]=
{
    -1,0,
    0,-1,
    0,1,
    1,0
};
int N, M, sx, sy, theEnd, ans;
bool within(int x, int y)       //是否还在图内
{
    return (x>=0 && y>=0 && x<N && y<M);
}
char mp[maxN][maxN];
bool vis[1<<16][maxN][maxN][maxN][maxN];    //是否遍历过这样的点
struct node
{
    int getRode, x1, y1, x2, y2, t;     //已经遍历过的路,(一号人)、(二号人)、已经花费时间
    node(int a=0, int b=0, int c=0, int d=0, int f=0, int g=0)
    {
        getRode=a;  x1=b;   y1=c;
        x2=d;   y2=f;   t=g;
    }
};
void bfs(int x, int y)
{
    memset(vis, false, sizeof(vis));
    vis[1<<(x*M+y)][x][y][x][y]=true;
    queue<node> Q;
    Q.push(node(1<<(x*M+y), x, y, x, y, 0));
    while(!Q.empty())
    {
        node u=Q.front();
        Q.pop();
        int id=u.getRode, x1=u.x1, y1=u.y1, x2=u.x2, y2=u.y2, t=u.t;
        if(id==theEnd) { ans=t; return; }
        for(int i=0; i<4; i++)
        {
            int xx1=x1+dir[i][0], yy1=y1+dir[i][1];
            if(!within(xx1, yy1) || mp[xx1][yy1]=='X') continue;
            for(int j=0; j<4; j++)
            {
                int xx2=x2+dir[j][0], yy2=y2+dir[j][1];
                int newId=(id | (1<<(xx1*M+yy1)) ) | 1<<((xx2*M+yy2));
                if(!within(xx2, yy2) || mp[xx2][yy2]=='X' || vis[newId][xx1][yy1][xx2][yy2]) continue;
                vis[newId][xx1][yy1][xx2][yy2]=true;
                Q.push(node(newId, xx1, yy1, xx2, yy2, t+1));
            }
        }
    }
}
int main()
{
    while(scanf("%d%d",&N,&M)!=EOF)
    {
        theEnd=0;
        for(int i=0; i<N; i++)
        {
            scanf("%s",mp[i]);
            for(int j=0; j<M; j++)
            {
                if(mp[i][j]=='O') { theEnd|=1<<(i*M+j); }
                else if(mp[i][j]=='S') { sx=i; sy=j; theEnd|=1<<(i*M+j); }
            }
        }
        bfs(sx, sy);
        printf("%d\n", ans);
    }
    return 0;
}

做这题的时候还有些尴尬,一开始写完子函数,然后就直接输出ans,后来发现一直没有答案,结果......一直没有调用子函数。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Wuliwuliii

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

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

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

打赏作者

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

抵扣说明:

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

余额充值