孤岛营救问题

孤岛营救问题

时空限制1000ms / 256MB

题目描述

1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。迷宫的外形是一个长方形,其南北方向被划分为 N 行,东西方向被划分为 M 列,于是整个迷宫被划分为 N×M 个单元。每一个单元的位置可用一个有序数对(单元的行号,单元的列号)来表示。南北或东西方向相邻的 2 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分成P 类,打开同一类的门的钥匙相同,不同类门的钥匙不同。

大兵瑞恩被关押在迷宫的东南角,即 (N,M) 单元里,并已经昏迷。迷宫只有一个入口,在西北角。也就是说,麦克可以直接进入 (1,1) 单元。另外,麦克从一个单元移动到另一个相邻单元的时间为 1,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。

试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。

输入输出格式

输入格式:

第 1 行有 3 个整数,分别表示 N,M,P 的值。

第 2 行是 1 个整数 K,表示迷宫中门和墙的总数。

第 I+2 行(1IK),有 5 个整数,依次为Xi1,Yi1,Xi2,Yi2,Gi

  • Gi1 时,表示 (Xi1,Yi1) 单元与(Xi2,Yi2) 单元之间有一扇第 Gi 类的门

  • Gi=0 时,表示 (Xi1,Yi1) 单元与 (Xi2,Yi2) 单元之间有一堵不可逾越的墙(其中,Xi1Xi2+Yi1Yi2=1,0GiP)。

第 K+3 行是一个整数 S,表示迷宫中存放的钥匙总数。

第 K+3+J 行(1JS),有 3 个整数,依次为Xi1,Yi1,Qi:表示第 J 把钥匙存放在 (Xi1,Yi1)单元里,并且第 J 把钥匙是用来开启第 Qi 类门的。(其中 P1QiP)。

输入数据中同一行各相邻整数之间用一个空格分隔。

输出格式:

将麦克营救到大兵瑞恩的最短时间的值输出。如果问题无解,则输出 1。

输入输出样例

输入样例: 
4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2
4 2 1
输出样例: 
14

说明

Xi1Xi2+Yi1Yi2=1,0GiP

 1QiP

N,M,P10,K<150,S14

题目链接:https://www.luogu.org/problemnew/show/P4011


状态压缩+BFS。最近感觉做了不少这样的bfs题,大思路就是对每种状态都记录一下最优答案,以能否更新当前状态作为bfs的条件。
ps:题目有坑,一个点可以放多把钥匙。
#include<bits/stdc++.h>
#define N 105
using namespace std;

struct ss
{
    int v,next,type;
};
ss edg[N*10];
int head[N],now_edge=0;

void addedge(int u,int v,int type)
{
    edg[now_edge]=(ss){v,head[u],type};
    head[u]=now_edge++;
    edg[now_edge]=(ss){u,head[v],type};
    head[v]=now_edge++;
}

vector<int>key[N];
int ans=INT_MAX;
int dp[N][1<<10];

struct orz
{
    int x,mykey,time;
};

int n,m;
void bfs()
{
    queue<orz>q;
    memset(dp,0x3f3f3f3f,sizeof(dp));

    int now_key=0;
    for(int j=0;j<key[1].size();j++)
    if(!(now_key&(1<<(key[1][j]-1))))now_key+=(1<<(key[1][j]-1));

    q.push((orz){1,now_key,0});

    while(!q.empty())
    {
        orz now=q.front();
        q.pop();
        
        if(now.x==n*m)
        {
            ans=min(ans,now.time);
            continue;
        }
        
        for(int i=head[now.x];i!=-1;i=edg[i].next)
        {
            ss e=edg[i];
            if(e.type==-1)continue;
            if(e.type==0||(e.type>0&&(now.mykey&(1<<(e.type-1)))))
            {
                if(dp[e.v][now.mykey]>now.time+1)
                {
                    dp[e.v][now.mykey]=now.time+1;
                    if(key[e.v].size())
                    {
                        int now_key=now.mykey;
                        for(int j=0;j<key[e.v].size();j++)
                        if(!(now_key&(1<<(key[e.v][j]-1))))now_key+=(1<<(key[e.v][j]-1));
            
                        q.push((orz){e.v,now_key,now.time+1});
                    }
                    else
                        q.push((orz){e.v,now.mykey,now.time+1});
                }
            }
        }
    }
}
int Map[N][N]={0};

int main()
{
    int p;
    memset(head,-1,sizeof(head));
    scanf("%d %d %d",&n,&m,&p);
    int k;
    scanf("%d",&k);
    while(k--)
    {
        int a,b,c,d,e;
        scanf("%d %d %d %d %d",&a,&b,&c,&d,&e);
        if(!e)e=-1;
        Map[(a-1)*m+b][(c-1)*m+d]=Map[(c-1)*m+d][(a-1)*m+b]=e;
    }
    
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    {
        if(i+1<=n)addedge((i-1)*m+j,((i+1)-1)*m+j,Map[(i-1)*m+j][((i+1)-1)*m+j]);
        if(j+1<=m)addedge((i-1)*m+j,(i-1)*m+j+1,Map[(i-1)*m+j][(i-1)*m+j+1]);
    }
        
    scanf("%d",&k);
    while(k--)
    {
        int a,b,c;
        scanf("%d %d %d",&a,&b,&c);
        key[(a-1)*m+b].push_back(c);
    }
    
    bfs();
    printf("%d\n",ans==INT_MAX ? -1 : ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/tian-luo/p/9697356.html
今日推荐