点此看题面

大致题意: 有一个\(N*M\)的四联通迷宫,相邻两个可能互通,可能有一扇门,也可能有一堵墙。对于第\(i\)类的门,你需要有第\(i\)类的钥匙才可以通过。问你从\((1,1)\)到达\((N,M)\)的最短路。

第一步:建图

看到种类数\(≤10\),应该不难想到状压吧!而且,我们还可以给每个格子一个编号(计算方法:\(pos(x,y)=(x-1)*m+y\))。

我们可以用\(key_i\)来表示编号为\(i\)的格子上有的钥匙状压之后的结果,并用\(dis_{i,j}\)来表示从\((1,1)\)出发,到达编号为\(i\)的节点时拥有的钥匙种类状压之后的结果为\(j\)的最短路径。

接下来,我们可以枚举每一个节点\(i\)与其一个相邻的节点\(j\),然后分类讨论:

  • 如果它们互通:在它们之间建一条边权为1的边。
  • 如果它们之间有一扇门:假设这扇门的种类为\(x\),就在他们之间建一条边权为\(2^x\)的边。
  • 如果它们之间有一堵墙:不建边。

其中,边权就相当于走这条边的条件,一定要当前拥有的钥匙含有开启这扇门的钥匙才行。

第二步:跑最(wang)短(luo)路(liu)

建完了图,就可以开始跑最短路了,当然,这题作为网络流24题之一,你一定要写网络流也没人拦你。

一开始初始化拥有的钥匙状压后的结果为1(不然就无法过边权为1的边),然后,每到达一个节点,就可以更新拥有的钥匙后的状压结果了。

最短路的过程应该还是比较简单的,这题难就难在建图。

代码

#include<bits/stdc++.h>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define abs(x) ((x)<0?-(x):(x))
#define LL long long
#define ull unsigned long long
#define swap(x,y) (x^=y,y^=x,x^=y)
#define tc() (A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++)
#define pc(ch) (pp_<100000?pp[pp_++]=(ch):(fwrite(pp,1,100000,stdout),pp[(pp_=0)++]=(ch)))
#define N 10
#define pos(x,y) ((x-1)*m+y)
#define add(x,y,z) (e[++ee].to=y,e[ee].nxt=lnk[x],e[lnk[x]=ee].val=z)
int pp_=0;char ff[100000],*A=ff,*B=ff,pp[100000];
using namespace std;
int n,m,s,ans=1e9,ee=0,Inqueue[N*N+5][1<<N+1],dis[N*N+5][1<<N+1],lnk[N*N+5],keys[N*N+5],f[N*N+5][N*N+5];
struct edge
{
int to,nxt,val;
}e[((N*N)<<2)+5];
struct Status
{
int x,v;
}q[((N*N)<<N+1)+5];
inline void read(int &x)
{
x=0;int f=1;static char ch;
while(!isdigit(ch=tc())) f=ch^'-'?1:-1;
while(x=(x<<3)+(x<<1)+ch-48,isdigit(ch=tc()));
x*=f;
}
inline void write(int x)
{
if(x<0) pc('-'),x=-x;
if(x>9) write(x/10);
pc(x%10+'0');
}
inline void SPFA()//跑最短路
{
register int i,j,H=Inqueue[1][1]=1,T=1,maxx=1<<s+1,MOD=(N*N)<<N+1;register Status k;q[1]=(Status){1,1};
for(i=1;i<=n*m;++i) for(j=0;j<maxx;++j) dis[i][j]=1e9;dis[1][1]=0;
while((H%=MOD)^(T+1))//只要队列没有空
{
k=q[H++],Inqueue[k.x][k.v]=0,dis[k.x][k.v|keys[k.x]]=min(dis[k.x][k.v|keys[k.x]],dis[k.x][k.v]),k.v|=keys[k.x];//更新当前拥有的钥匙的数量
for(i=lnk[k.x];i;i=e[i].nxt)//枚举当前节点能到达的每一个节点
{
if((k.v&e[i].val)^e[i].val) continue;//如果不满足条件,就跳过
if(dis[k.x][k.v]+1<dis[e[i].to][k.v])//如果更短就更新最短距离
{
dis[e[i].to][k.v]=dis[k.x][k.v]+1;
if(!Inqueue[e[i].to][k.v]) Inqueue[e[i].to][k.v]=1,q[(++T)%=MOD]=(Status){e[i].to,k.v};//如果不在队列中,就将其加入队列
}
}
}
for(i=0;i<maxx;++i) ans=min(ans,dis[n*m][i]);//求出最优的答案
}
int main()
{
register int i,j,t,x,y,z;
for(read(n),read(m),read(s),i=1;i<=n*m;++i) for(j=1;j<=n*m;++j) f[i][j]=-1;
for(read(t);t;--t)
{
static int u,v;
read(x),read(y),u=pos(x,y),read(x),read(y),v=pos(x,y),read(x),f[u][v]=f[v][u]=x;
if(x) add(u,v,1<<f[u][v]),add(v,u,1<<f[u][v]);//如果这不是一堵墙,就新建一条边
}
for(i=1;i<=n;++i)
{
for(j=1;j<=m;++j)
{
//对于互通的情况建边
if(i>1&&!(~f[pos(i,j)][pos(i-1,j)])) add(pos(i,j),pos(i-1,j),1);
if(i<n&&!(~f[pos(i,j)][pos(i+1,j)])) add(pos(i,j),pos(i+1,j),1);
if(j>1&&!(~f[pos(i,j)][pos(i,j-1)])) add(pos(i,j),pos(i,j-1),1);
if(j<m&&!(~f[pos(i,j)][pos(i,j+1)])) add(pos(i,j),pos(i,j+1),1);
}
}
for(read(t);t;--t) read(x),read(y),read(z),keys[pos(x,y)]|=1<<z;//读入每一把钥匙,更新每一个位置的钥匙种类状压后的值
return SPFA(),write(ans^1000000000?ans:-1),fwrite(pp,1,pp_,stdout),0;
}

【洛谷4011】孤岛营救问题(状压SPFA)的更多相关文章

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

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

  2. 【题解】洛谷P3959 [NOIP2017TG] 宝藏(状压DP+DFS)

    洛谷P3959:https://www.luogu.org/problemnew/show/P3959 前言 NOIP2017时还很弱(现在也很弱 看出来是DP 但是并不会状压DP 现在看来思路并不复 ...

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

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

  4. 洛谷 P2473 [SCOI2008]奖励关(状压dp+期望)

    题面 luogu 题解 \(n \leq 15\) 状压 \(f[i][S]\)表示第\(i\)轮,吃过的集合为\(S\) 正着转移好像有点复杂 考虑逆推转移(正着转移应该也行) \(f[i][S]\ ...

  5. 洛谷 P1278 单词游戏 【状压dp】

    题目描述 Io和Ao在玩一个单词游戏. 他们轮流说出一个仅包含元音字母的单词,并且后一个单词的第一个字母必须与前一个单词的最后一个字母一致. 游戏可以从任何一个单词开始. 任何单词禁止说两遍,游戏中只 ...

  6. 洛谷P2761 软件补丁问题 [状压DP,SPFA]

    题目传送门 软件补丁问题 题目描述 T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序.每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又 ...

  7. 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]

    题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...

  8. 洛谷P2761 软件补丁问题(状压DP,SPFA)

    题意 描述不清... Sol 网络流24题里面怎么会有状压dp?? 真是狗血,不过还是简单吧. 直接用$f[sta]$表示当前状态为$sta$时的最小花费 转移的时候枚举一下哪一个补丁可以搞这个状态 ...

  9. 洛谷 P3622 [APIO2007]动物园【状压dp】

    看成网络流建图想了好久... 实际上5个是可以状压的 设f[i][k]为到第i个围栏状态为k的方案数,因为考虑到重复,设g[i][k]记录i开始,状态为k的孩子有几个 状态转移很好想:f[j][k]= ...

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

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

随机推荐

  1. vue -- 打包资源正确引用及背景图引入

    一般情况下,通过webpack+vuecli默认打包的css.js等资源,路径都是绝对的. 但当部署到带有文件夹的项目中,这种绝对路径就会出现问题,因为把配置的static文件夹当成了根路径,那么要解 ...

  2. Mice and Holes 单调队列优化dp

    Mice and Holes 单调队列优化dp n个老鼠,m个洞,告诉你他们的一维坐标和m个洞的容量限制,问最小总距离.1 ≤ n, m ≤ 5000. ​ 首先列出朴素的dp方程:\(f[i][j] ...

  3. web综合案例01

    web综合案例01 ... .... 内容待添加

  4. css奇技淫巧—border-radius

    官方介绍: 浏览器支持:IE9+, Firefox 4+, Chrome, Safari 5+,和Opera支持border-radius属性. border-radius 属性是一个最多可指定四个 ...

  5. java监听器原理理解与实现

    监听器模型涉及以下三个对象,模型图如下: (1)事件:用户对组件的一个操作,称之为一个事件(2)事件源:发生事件的组件就是事件源(3)事件监听器(处理器):监听并负责处理事件的方法 执行顺序如下: 1 ...

  6. 如何直接修改cf,of等标志位的值?

    如何直接修改 cf,of 等 标志寄存器位的值? 我记得在哪个教程里见过,但是不太记得了… 貌似是在yjx驱动教程里面… 我想弄这个的原因是想验证 网上查到的 各种跳转语句(ja,jl,jg等) 需要 ...

  7. Spring学习(六)整合web开发

    https://www.cnblogs.com/Leo_wl/p/4459274.html 1.加载Spring核心配置文件 //1.加载Spring配置文件,根据创建对对象 ApplicationC ...

  8. git merge的参数--squash的用处

    本地分支处理问题的过程中一般都是commit在本地分支,当验证完毕后就需要merge到baseline上. 在不懂merge的--squash这个参数前,我一般是这么操作的: 1.在本地分支" ...

  9. kolla-ansible-----rally模块

    Rally简介 Rally是OpenStack社区推出开源测试工具,可用于对OpenStack各个组件进行性能测试. 通过使用Rally组件,用户可完成OpenStack云计算平台的安装部署.功能验证 ...

  10. PHP面试题基础问题

    1.对于大流量的网站,您采用什么样的方法来解决访问量问题? 首先,确认服务器硬件是否足够支持当前的流量 其次,优化数据库访问. 第三,禁止外部的盗链. 第四,控制大文件的下载. 第五,使用不同主机分流 ...