UVa 1601 The Morning after Halloween 双向bfs

本文介绍了一种解决迷宫寻路问题的高效算法,利用多目标双向BFS策略,在考虑障碍物限制的情况下,寻找小写字母(鬼)到大写字母的最短路径。通过构建图并采用哈希方法记录边状态,大幅提高了搜索效率。

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

题目:

在一个网格w*h(w,h<=16)中有n个小写字母(代表鬼),要求它们分别移动到对应的大写字母里,每步可以有多个鬼同时移动,但每步结束后任意两个鬼不能占同一个位置,也不能在一步之内交换位置。

思路:

这题目如果纯暴力搜的话会超时,因为每步都有5^3种情况。

题目中有个条件是任何一个2*2的子网格中至少有一个障碍物,所以我们可以先建个图,将图中每个点能走的点建成边,这样搜索的时候会节省很多时间。

搜索的时候可以用双向bfs进行搜索,即从起点和终点分别开始搜索。

记录每个边状态的时候可以用hash的方法记录,因为不加障碍物一共二百个点,用hash的话只需要二进制24位就行。

代码如下:

代码是参考着别人写的,写的时候一脸蒙蔽。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=205;
int w,h,n;
char a[20][20];
int pos[5][2]={{0,0},{1,0},{-1,0},{0,1},{0,-1}};
int s[5],e[5];
int deg[maxn];
int edge[maxn][maxn];
int vis[maxn][maxn][maxn];
int step[maxn][maxn][maxn];
//hash
int change(int a,int b,int c)
{
    return (a<<16)|(b<<8)|c;
}
//判断是否冲突
bool isSame(int a1,int b1,int a2,int b2)
{
    return ((a2==b2)||(a1==b2&&b1==a2));
}
int bfs ()
{
    queue<int>q[2];
    vis[s[0]][s[1]][s[2]]=1;
    vis[e[0]][e[1]][e[2]]=2;
    step[s[0]][s[1]][s[2]]=0;
    step[e[0]][e[1]][e[2]]=1;
    q[0].push(change(s[0],s[1],s[2]));
    q[1].push(change(e[0],e[1],e[2]));
    while(!q[0].empty()||!q[1].empty())
    {
        int Size1=q[0].size(),Size2=q[1].size();
        while(Size1--)
        {
            int now=q[0].front(); q[0].pop();
            //解码
            int a=(now>>16)&0xff,b=(now>>8)&0xff,c=now&0xff;
            for (int i=0;i<deg[a];i++)
            {
                int na=edge[a][i];
                for (int j=0;j<deg[b];j++)
                {
                    int nb=edge[b][j];
                    if(isSame(a,b,na,nb)) continue;
                    for (int k=0;k<deg[c];k++)
                    {
                        int nc=edge[c][k];
                        if(isSame(a,c,na,nc)||isSame(b,c,nb,nc)) continue;
                        if(vis[na][nb][nc]==0)
                        {
                            step[na][nb][nc]=step[a][b][c]+1;
                            vis[na][nb][nc]=1;
                            q[0].push(change(na,nb,nc));
                        }
                        else if(vis[na][nb][nc]==2)
                        {
                            return step[a][b][c]+step[na][nb][nc];
                        }
                    }
                }
            }
        }
        while(Size2--)
        {
            int now=q[1].front(); q[1].pop();
            int a=(now>>16)&0xff,b=(now>>8)&0xff,c=now&0xff;
            for (int i=0;i<deg[a];i++)
            {
                int na=edge[a][i];
                for (int j=0;j<deg[b];j++)
                {
                    int nb=edge[b][j];
                    if(isSame(a,b,na,nb)) continue;
                    for (int k=0;k<deg[c];k++)
                    {
                        int nc=edge[c][k];
                        if(isSame(a,c,na,nc)||isSame(b,c,nb,nc)) continue;
                        if(vis[na][nb][nc]==0)
                        {
                            step[na][nb][nc]=step[a][b][c]+1;
                            vis[na][nb][nc]=2;
                            q[1].push(change(na,nb,nc));
                        }
                        else if(vis[na][nb][nc]==1)
                        {
                            return step[a][b][c]+step[na][nb][nc];
                        }
                    }
                }
            }
        }
    }
    return -1;

}
int main()
{
    while(scanf("%d%d%d",&w,&h,&n)!=EOF)
    {
        int cnt=0;
        int x[maxn],y[maxn];
        int id[maxn][maxn];
        if(w==0&&h==0&&n==0) break;
        getchar();
        for (int i=0;i<h;i++) gets(a[i]);
        //将起点和终点位置记下
        for (int i=0;i<h;i++)
        {
            for (int j=0;j<w;j++)
            {
                if(a[i][j]!='#')
                {
                    x[cnt]=i,y[cnt]=j,id[i][j]=cnt;
                    if(islower(a[i][j])) s[a[i][j]-'a']=cnt;
                    else if(isupper(a[i][j])) e[a[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]+pos[j][0];
                int ty=y[i]+pos[j][1];
                if(a[tx][ty]!='#')
                {
                    edge[i][deg[i]++]=id[tx][ty];
                }
            }
        }
        //如果不够三个点,则添加至三个点
        if(n<=2)
        {
            deg[cnt]=1;
            edge[cnt][0]=cnt;
            s[2]=e[2]=cnt++;
        }
        if(n<=1)
        {
            deg[cnt]=1;
            edge[cnt][0]=cnt;
            s[1]=e[1]=cnt++;
        }
        //初始化
        memset (vis,0,sizeof(vis));
        memset (step,0,sizeof(step));
        if(s[0]==e[0]&&s[1]==e[1]&&s[2]==e[2]) printf("0\n");
        else printf("%d\n",bfs());
    }
    return 0;
}

 

内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值