P4011 孤岛营救问题

题意

题目描述

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

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

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

输入输出格式

输入格式:

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

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

第\(I+2\)行\((1 \leq I \leq K)\),有\(5\)个整数,依次为\(X_{i1},Y_{i1},X_{i2},Y_{i2},G_i\):

  • 当\(G_i \geq 1\)时,表示\((X_{i1},Y_{i1})\)单元与\((X_{i2},Y_{i2})\)单元之间有一扇第\(G_i\)类的门
  • 当\(G_i=0\)时,表示\((X_{i1},Y_{i1})\)单元与\((X_{i2},Y_{i2})\)单元之间有一堵不可逾越的墙(其中,\(|X_{i1}-X_{i2}|+|Y_{i1}-Y_{i2}|=1\),\(0 \leq G_i \leq P\))。

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

第\(K+3+J\)行\((1 \leq J \leq S)\),有\(3\)个整数,依次为\(X_{i1},Y_{i1},Q_i\):表示第\(J\)把钥匙存放在\((X_{i1},Y_{i1})\)单元里,并且第\(J\)把钥匙是用来开启第\(Q_i\)类门的。(其中\(1 \leq Q_i \leq P\))。

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

输出格式:

将麦克营救到大兵瑞恩的最短时间的值输出。如果问题无解,则输出\(-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

说明

\(|X_{i1}-X_{i2}|+|Y_{i1}-Y_{i2}|=1,0 \leq G_i \leq P\)

\(1 \leq Q_i \leq P\)

\(N,M,P \leq 10, K<150,S \leq 14\)

思路

这题我调了一晚上,本来想第二天给你们装逼的,可惜没调出来。 --digger_sun

这是一道很不错的题,可以用多种方式\(AC\):\(A^*\)、最短路、网络流...在这里我选择的是状态压缩+最短路。

定义\(dis[i][j]\)表示在\(i\)号结点时拥有的钥匙状态为\(j\)的最短路径长度。其中,\(j\)的二进制表示下第\(k\)位表示是否拥有钥匙\(k\)。建图时,互相能连通的两点之间距离都为一,走到有钥匙的点时一定拿钥匙,稳妥地处理输入信息,就能\(AC\)了,码量也不大。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
const int INF=0x3f3f3f3f;
int n,m,p,k,ans=INF,dis[105][1<<15],G[105][105],gate[105][105],key[105];
int cnt,top[105],to[1005],len[1005],ned[1005],nex[1005];
bool vis[105][1<<15];
int a[2]={+1,+0};
int b[2]={+0,+1};
int read()
{
int re=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) re=(re<<3)+(re<<1)+ch-'0',ch=getchar();
return re;
}
inline int f(int x,int y){return (x-1)*m+y;}
inline void add_edge(int x,int y,int z,int w)
{
to[++cnt]=y,len[cnt]=z,ned[cnt]=w,nex[cnt]=top[x],top[x]=cnt;
to[++cnt]=x,len[cnt]=z,ned[cnt]=w,nex[cnt]=top[y],top[y]=cnt;
}
void SPFA()
{
memset(dis,0x3f,sizeof dis);
queue<PII>Q;
dis[1][key[1]]=0;
Q.push(make_pair(1,key[1]));
while(!Q.empty())
{
int now=Q.front().first,con=Q.front().second;Q.pop();
vis[now][con]=false;
for(int i=top[now];i;i=nex[i])
if((ned[i]&con)==ned[i])
if(dis[to[i]][con|key[to[i]]]>dis[now][con]+len[i])
{
dis[to[i]][con|key[to[i]]]=dis[now][con]+len[i];
if(!vis[to[i]][con|key[to[i]]])
{
vis[to[i]][con|key[to[i]]]=true;
Q.push(make_pair(to[i],con|key[to[i]]));
}
}
}
}
int main()
{
n=read(),m=read(),p=read(),k=read();
while(k--)
{
int x=read(),y=read(),xx=read(),yy=read(),g=read();
if(!g) G[f(x,y)][f(xx,yy)]=G[f(xx,yy)][f(x,y)]=INF;
else gate[f(x,y)][f(xx,yy)]=gate[f(xx,yy)][f(x,y)]=(1<<(g-1));
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int w=0;w<2;w++)
{
int x=i+a[w],y=j+b[w];
if(x<=0||x>n||y<=0||y>m) continue;
add_edge(f(i,j),f(x,y),G[f(i,j)][f(x,y)]==INF?INF:1,gate[f(i,j)][f(x,y)]);
}
k=read();
while(k--)
{
int x=read(),y=read(),z=read();
key[f(x,y)]|=(1<<(z-1));
}
SPFA();
for(int i=0;i<(1<<p);i++) ans=min(ans,dis[f(n,m)][i]);
printf("%d",ans==INF?-1:ans);
return 0;
}

Luogu P4011 孤岛营救问题(状态压缩+最短路)的更多相关文章

  1. Luogu P4011 孤岛营救问题

    题目链接 \(Click\) \(Here\) 注意坑点:一个地方可以有多把钥匙. 被卡了一会,调出来发现忘了取出来实际的数字,直接把二进制位或上去了\(TwT\),其他的就是套路的分层图最短路.不算 ...

  2. 洛谷 P4011 孤岛营救问题【最短路+分层图】

    题外话:昨夜脑子昏沉,今早一调试就过了...错误有:我忘记还有墙直接穿墙过...memset初始化INF用错了数...然后手残敲错一个状态一直过不了样例...要是这状态去比赛我简直完了......or ...

  3. luogu P2704 炮兵阵地(经典状态压缩DP)

    方格有m*n个格子,一共有2^(m+n)种排列,很显然不能使用暴力法,因而选用动态规划求解. 求解DP问题一般有3步,即定义出一个状态 求出状态转移方程 再用算法实现.多数DP题难youguan点在于 ...

  4. P4011 孤岛营救问题

    \(\color{#0066ff}{题目描述}\) 1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克 ...

  5. 洛谷P4011 孤岛营救问题(状压+BFS)

    传送门 和网络流有半毛钱关系么…… 可以发现$n,m,p$都特别小,那么考虑状压,每一个状态表示位置以及钥匙的拥有情况,然后每次因为只能走一步,所以可以用bfs求出最优解 然后是某大佬说的注意点:每个 ...

  6. 【Luogu】P2258子矩阵(状态压缩,DP)

    233今天蒟蒻我连文化课都没听光想着这个了 然后我调了一下午终于过了!!! 一看数据范围似乎是状压,然而216等于65536.开一个65536*65536的二维数组似乎不太现实. 所以Rqy在四月还是 ...

  7. 洛谷 P4011 孤岛营救问题【bfs】

    注意: 一个点可能有多把钥匙,所以把每个点有钥匙的情况状压一下 两个点之间有障碍的情况只给出了单向,存的时候记得存一下反向 b[i][j]表示当前点拥有钥匙的状态,g[x1][y1][x2][y2]表 ...

  8. 洛谷 [P4011] 孤岛营救问题

    状压+BFS 通过观察数据范围可知,我们应该状压钥匙种类,直接BFS即可 注意,一个点处可能不知有一把钥匙 #include <iostream> #include <cstdio& ...

  9. P2622 关灯问题II (状态压缩,最短路)

    题目链接 Solution 这道题算是很经典的状压问题了,好题. 考虑到 \(n\) 的范围仅为 \(10\) , 那么也就是说所有状态压起来也只有 \(1024\) 种情况. 然后我们发现 \(m\ ...

随机推荐

  1. <数据可视化>Matplotlib(2D+3D)

    1.Matplotlib介绍(2D) Matplotlib 是 Python 2D-绘图领域使用最广泛的套件.它能让使用者很轻松地将数据图形化,并且提供多样化的输出格式. pylab 是 matplo ...

  2. Pthread spinlock自旋锁

    锁机制(lock) 是多线程编程中最常用的同步机制,用来对多线程间共享的临界区(Critical Section) 进行保护. Pthreads提供了多种锁机制,常见的有:1) Mutex(互斥量): ...

  3. vue初学之node.js安装、cnpm安装、vue初体验

    1. 如果本机没有安装node运行环境,请下载node 安装包进行安装.地址:https://nodejs.org/en/ 2.装完,使用cmd命令行输入:node -v回车 如果输出版本号则成功. ...

  4. No packages marked for update

    问题:用yum安装docker,更新yum存储时,报以下错误,导致yum坏了 [root@localhost yum.repos.d]# vi docker.repo [root@localhost ...

  5. 读《深入PHP 面向对象、模式与实践》笔记

    1. include() 和require() 语句的不同在于它们如何处理错误.使用require()调用文件发生错误时,将会停止整个程序;调用include()时遇到相同的错误,则会生成警告并停止执 ...

  6. 新安装一个eclipse,导入一个web项目,右键点击项目选择Properties,找不到project facets和Server选项。

    解决方式: 1.点击:eclipse导航栏中点击Help->Install New Software 2.点击Add添加 3在弹出框中填写以下信息 name:keep(名字随便取) locati ...

  7. 中国剩余定理模数不互质的情况(poj 2891

    中国剩余定理模数不互质的情况主要有一个ax+by==k*gcd(a,b),注意一下倍数情况和最小 https://vjudge.net/problem/POJ-2891 #include <io ...

  8. 0903NOIP模拟测试赛后总结

    分-rank33.这次考试心态挂了. 拿到题目通读三道题,发现都十分恶心. 然后把时间押到了T1上.将近两个小时,打了个dfs,一直调调调. 最后没调出来,手模了个数据就把自己两个小时的思路hack了 ...

  9. 北京服务业占GDP比重达81.7%

    北京服务业占GDP比重达81.7% 2017-05-17 19:46:00 来源: 中国新闻网(北京)举报   0 易信 微信 QQ空间 微博 更多 (原标题:北京服务业占GDP比重达81.7%)   ...

  10. Struts2中param的作用

    1.页面传参与配置传参的区别:如果页面Form表单的参数在Action类中有相应的setter方法,则会优先取页面Form表单传过来的值,如果页面没有该属性同名的参数,则会从配置文件中取同名的参数值作 ...