The Morning after Halloween UVA - 1601 单向BFS 添加假节点减少代码量

本文介绍了一种基于迷宫寻路的算法实现,利用位运算优化状态表示,并通过设置虚拟点简化多目标寻路问题。文章详细展示了使用C++实现的广度优先搜索(BFS)算法过程,包括地图读取、路径寻找及冲突检测等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

紫书上的代码 有意思的是刘大牛用了位运算表示状态 其实用结构体也可以 输入用getsc++不让用, 后面换了fgets 引用了

https://zhidao.baidu.com/question/427775494.html 的答案

fgets的原型是
char* fgets(char* s, int n, FILE* fp);
参数数量比较多,有3个。而fgets相比于gets有一个显著的差别就是fgets会将行末的换行符算到读入的字符串里面。所以相同且正常(输入无错误,缓冲区够大)的情况下,fgets读入的字符串会比gets在末尾'\0'前面多一个换行符;行长度超出缓冲区大小时只读入前 n-1 个字符。因此,
gets(s);
相当于
fgets(s, sizeof(s), stdin);  
if(s[strlen(s) - 1] == '\n') s[strlen(s) - 1] = '\0';   // 去掉换行符
其实,末尾这个换行符是另有妙用的。

还有鬼数量不足3个设置假鬼也很有意思 设置一个假鬼点自环,同时只有他自己能到这个点,他也只有一条自环边,所以不影响正确答案。这样可以有效减少代码量

#include<bits/stdc++.h>
using namespace std;
int w,h,n;
int cnt=0;
char maze[25][25];
int x[405],y[405],deg[405];
int id[20][20];
int s[4],t[4];
int G[250][6];
int dx[]={0,1,-1,0,0};
int dy[]={0,0,0,1,-1};
inline bool conflict(int a, int b, int a2, int b2) {
  return a2 == b2 || (a2 == b && b2 == a);
}
inline int ID(int a, int b, int c) {
  return (a<<16)|(b<<8)|c;  //也可以用个结构存
}

int d[200][200][200];

int bfs(){
queue<int>q;
memset(d,-1,sizeof(d));
q.push(ID(s[0],s[1],s[2]));
d[s[0]][s[1]][s[2]]=0;
while(!q.empty()){
    int u=q.front();
    q.pop();
    int a=(u>>16)&0xff,b=(u>>8)&0xff,c=u&0xff;  //读取出8 8 8这3个8位
    if(a==t[0]&&b==t[1]&&c==t[2])return d[a][b][c];
    for(int i=0;i<deg[a];i++){
        int a2=G[a][i];
        for(int j=0;j<deg[b];j++){
                int b2=G[b][j];
            if(conflict(a,b,a2,b2))continue;
            for(int k = 0; k < deg[c]; k++) {
            int c2 = G[c][k];
            if(conflict(a, c, a2, c2)) continue;
            if(conflict(b, c, b2, c2)) continue;
            if(d[a2][b2][c2] != -1) continue;
            d[a2][b2][c2] = d[a][b][c]+1;
            q.push(ID(a2, b2, c2));
          }
        }
    }
}
return -1;

}


int main(){
while(scanf("%d%d%d",&w,&h,&n)==3&&w){
    memset(deg,0,sizeof(deg));
        cnt=0;
   getchar();

    for(int i=0;i<h;i++){
            fgets(maze[i],20,stdin);
        for(int j=0;j<w;j++){
            if(maze[i][j]!='#'){
                x[cnt]=i;y[cnt]=j;id[i][j]=cnt;
                if(islower(maze[i][j]))s[maze[i][j]-'a']=cnt;
                else if(isupper(maze[i][j]))t[maze[i][j]-'A']=cnt;
                cnt++;
            }
        }
    }

    for(int i=0;i<cnt;i++){
        deg[i]=0;
for(int j=0;j<5;j++){//注意 还有停下来的操作
    int tx=x[i]+dx[j];
    int ty=y[i]+dy[j];
    if(tx>=0&&tx<h&&ty>=0&&ty<w&&maze[tx][ty]!='#'){
        G[i][deg[i]++]=id[tx][ty];
      }
    }
}
//设置假鬼就一个方向自环 等于设置了一个虚拟点 这样可以减少代码量  把1 2个鬼的情况模拟成3个的情况又对答案没有影响
if(n<=2){
    deg[cnt]=1;G[cnt][0]=cnt;s[2]=t[2]=cnt++;  
}
if(n<=1){
    deg[cnt]=1;G[cnt][0]=cnt;s[1]=t[1]=cnt++;
}
printf("%d\n",bfs());


}
return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值