特殊迷宫

本文介绍了一种使用图遍历算法解决迷宫问题的方法,玩家需要找到最少传送门路径以逃离迷宫。通过二进制压缩技巧,算法有效地处理了钥匙和门的解锁条件。

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

【问题描述】

  小沐正处在一个特殊的迷宫里,他希望能尽快走出迷宫。
  该迷宫中有N个房间,初始时,小沐在1号房间,而出口在N号房间。迷宫的每一个房间中可能有着一些钥匙和一些传送门,一个传送门会单向地创造一条从房间X到房间Y的通道。另外,想要通过某个传送门,就必须具备一些种类的钥匙(每种钥匙都要有才能通过)。幸运的是,钥匙在打开传送门的封印后,并不会消失。
  然而,通过迷宫的传送门需要耗费大量的时间,因此,小沐希望通过尽可能少的传送门到达出口,你能告诉小沐这个数值吗?另外,小沐有可能不能逃出这个迷宫,如果是这样,请输出 “No Solution”。

【输入格式】

  输入的第一行三个整数 N,M,K,分别表示房间的数量、传送门的数量以及钥匙的种类数。接下来N行,每行K个0或1,若第i个数为1,则表示该房间内有第i种钥匙,若第i个数为0,则表示该房间内没有第i种钥匙。再接下来M行,每行先读入两个整数X,Y,表示该传送门是建立在X号房间,通向Y号房间的,再读入K个0或1,若第i个数为1,则表示通过该传送门需要i种钥匙,若第i个数为0,则表示通过该传送门不需要第i种钥匙。

【输出格式】

  输出一行一个 “No Solution”,或一个整数,表示最少通过的传送门数。

【输入样例】

【样例1】
 3 3 2
 1 0
 0 1
 0 0
 1 3 1 1
 1 2 1 0
 2 3 1 1

【样例2】
 20 40 0
 10 18
 18 14
 19 13
 4 14
 13 10
 5 18
 14 1
 13 13
 10 16
 19 11
 11 15
 10 18
 5 8
 12 19
 7 8
 18 6
 14 5
 9 5
 2 17
 13 14
 18 15
 8 18
 7 1
 13 5
 4 6
 17 4
 1 4
 10 10
 13 8
 19 2
 4 9
 3 3
 5 10
 17 5
 12 8
 19 11
 3 16
 17 10
 18 16
 13 13

【样例3】
 20 50 0
 8 10
 7 17
 5 11
 14 20
 20 16
 8 19
 12 11
 18 7
 17 5
 4 15
 16 11
 11 8
 10 12
 8 9
 16 8
 3 16
 1 6
 3 20
 6 10
 11 12
 6 8
 18 17
 14 17
 3 11
 4 19
 9 2
 8 6
 13 2
 5 2
 12 19
 8 10
 14 7
 6 12
 6 4
 13 2
 8 7
 13 19
 17 9
 3 14
 18 20
 2 14
 4 17
 20 15
 14 15
 2 15
 7 20
 12 12
 18 10
 15 9
 15 9

【输出样例】

【样例1】
 2

【样例2】
 No Solution
【样例3】
 4
 思路:
 题本身很简单。此题唯一的收获在于压缩,将所得的压缩二进制成整数。
 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
#define maxn 5005
#define maxm 6005
struct edge
{
    int to,next,w;
}e[maxm<<1];
int first[maxn],np=0,dist[maxn][2050],a[15];
int n,m,k,key[maxn];
bool inq[maxn][2050];
const int inf=1e7;
void addedge(int u,int v,int w)
{
    e[++np]=(edge){v,first[u],w};
    first[u]=np;
}
struct data
{
    int id,key;
};
int calc(int x,int y)
{
    int ans=0;
    memset(a,0,sizeof(a));
    for (int i=0;i<k;i++)
    {
        if (x%2==1||y%2==1)
        a[i]=1;
        x=x/2,y=y/2;
    }
    for (int i=0;i<k;i++)
    ans+=(a[i]<<i);
    return ans;
}
bool calc1(int x,int y)
{
    for (int i=0;i<k;i++)
    {
        if (x%2==0&&y%2==1)
        return 0;
        x=x/2,y=y/2;
    }
    return 1;
}
void BFS()
{
    data t;
    queue<data>q;
    inq[1][key[1]]=1;
    dist[1][key[1]]=0;
    q.push((data){1,key[1]});
    while(!q.empty())
    {
        t=q.front();
        q.pop();
        int i=t.id;
        for (int p=first[i];p;p=e[p].next)
        {
            int j=e[p].to,w=e[p].w;
            if (!calc1(t.key,w))
            continue;
            int ww=calc(t.key,key[j]);
            if (inq[j][ww])
            continue;
            dist[j][ww]=dist[i][t.key]+1;
            inq[j][ww]=1;
            q.push((data){j,ww});
        }
    }
}
void init()
{
    int x,u,v;
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=n;i++)
    {
        int di=0;
        for (int j=0;j<k;j++)
        {
            scanf("%d",&x);
            if (x==1)
            di+=(x<<j);
        }
        key[i]=di;
        //printf("%d\n",di);
    }
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        int di=0;
        for (int j=0;j<k;j++)
        {
            scanf("%d",&x);
            if (x==1)
            di+=(x<<j);
        }
        //printf("%d\n",di);
        addedge(u,v,di);
    }
}
void solve()
{
    int ans=1e7;
    BFS();
    int kk=(1<<(k+1))-1;
    for (int i=0;i<=kk;i++)
    if (ans>dist[n][i]&&dist[n][i]!=0)
    ans=dist[n][i];
    if (ans!=1e7)
    printf("%d",ans);
    else
    printf("No Solution");
}
int main()
{
    //freopen("maze.in","r",stdin);
    //freopen("maze.out","w",stdout);
    //freopen("in.txt","r",stdin);
    init();
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值