孤岛营救问题(最短路)

本题题目其实与网络流无关,一看题目发现是求从一个地方到另一个地方((1,1)到(n,m))的最快时间,很明显就是求最短路。

特别的是本题相邻的两个格子之间可能存在墙和或门,可能是死路也可能需要对应的钥匙开门,所以为啦解决对应的钥匙开门的问题,就可以来状态压缩,在dp[i][j][k]的第三维用二进制,既简单的位运算来表示在i行j列拥有钥匙状态为k时的最快速度。然后再bfs一遍(bfs的过程中可以写个判断函数,看能否开门或继续往下走,然后如果比此时的dp数组还小,则更新dp数组),最后for循环一遍找在dp数组在(n,m)时的最小值即可,最后记得特判一下-1。

      
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <vector>
#include <queue>

#define M 15
#define INF 0x7fffffff/2

using namespace std;

int n,m,k,p,s;
int dp[M][M][1<<M];
int door[M][M][M][M];
int fmap[M][M];

int fx[5]={0,-1,0,1,0};
int fy[5]={0,0,1,0,-1};

struct node
{
    int x;
    int y;
    int key;
    int dis;
}str1,str2;

queue <node> q;

bool check(int x1,int y1,int x2,int y2,int key1)
{
    int tmp=door[x1][y1][x2][y2];
    if(tmp==-1)
        return true;
    else
    {
        if(tmp==0)
            return false;
        else
        {
            if(key1&(1<<(tmp-1)))
                return true;
            else
                return false;
        }
    }
}

void bfs()
{
    str1.x=1;
    str1.y=1;
    str1.key=0;
    str1.dis=0;
    q.push(str1);
    while(!q.empty())
    {
        str1=q.front();
        q.pop();
        for(int i=1;i<=4;i++)
        {
            str2.x=str1.x+fx[i];
            str2.y=str1.y+fy[i];
            if(str2.x>=1&&str2.x<=n&&str2.y>=1&&str2.y<=m&&check(str1.x,str1.y,str2.x,str2.y,str1.key))
            {
                str2.dis=str1.dis+1;
                str2.key=str1.key;
                str2.key |= fmap[str2.x][str2.y];
                if(str2.dis<dp[str2.x][str2.y][str2.key])
                {
                    dp[str2.x][str2.y][str2.key]=str2.dis;
                    q.push(str2);
                }
            }
        }
    }
}

void init()
{
    scanf("%d%d%d",&n,&m,&p);
    scanf("%d",&k);
    memset(door,-1,sizeof(door));
    memset(fmap,0,sizeof(fmap));

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    for(int k=0;k<(1<<p);k++)
        dp[i][j][k]=INF;

    for(int i=1;i<=k;i++)
    {
        int x1,y1,x2,y2,G;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&G);
        door[x1][y1][x2][y2]=G;
        door[x2][y2][x1][y1]=G;
    }
    scanf("%d",&s);
    for(int i=1;i<=s;i++)
    {
        int x,y,Q;
        scanf("%d%d%d",&x,&y,&Q);
        fmap[x][y] |= 1<<(Q-1);
    }
}

int main()
{
    freopen("t14.in","r",stdin);
    freopen("t14.out","w",stdout);
    init();
    bfs();
    int ans=INF;
    for(int i=0;i<(1<<p);i++)
    {
        if(ans>dp[n][m][i])
            ans=dp[n][m][i];
    }
    if(ans==INF)
        printf("-1\n");
    else
        printf("%d\n",ans);

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值