44. [CTSC1999] 解救大兵瑞恩

★★☆ 输入文件:rescue.in 输出文件:rescue.out 简单对照

时间限制:1 s 内存限制:128 MB

问题描写叙述

1944年,特种兵麦克接到国防部的命令,要求马上赶赴太平洋上的一个孤岛。营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,可是幸好麦克得到了迷宫的地形图。

迷宫的外形是一个长方形,其在南北方向被划分为N行,在东西方向被划分为M列,于是整个迷宫被划分为N*M个单元。我们用一个有序数对(单元的行号,单元的列号)来表示单元位置。南北或东西方向相邻的两个单元之间能够互通,或者存在一扇锁着的门,又或者存在一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,而且全部的门被分为P类,打开同一类的门的钥匙同样。打开不同类的门的钥匙不同。

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

你的任务是帮助麦克以最快的方式抵达瑞恩所在单元。营救大兵瑞恩。

输入

第一行是三个整数,依次表示N,M,P的值;

第二行是一个整数K,表示迷宫中门和墙的总个数;

第I+2行(1<=I<=K)。有5个整数,依次为Xi1,Yi1,Xi2,Yi2,Gi:

当Gi>=1时。表示(Xi1,Yi1)单元与(Xi2,Yi2)单元之间有一扇第Gi类的门,当Gi=0时。表示(Xi1,Yi1)单元与(Xi2,Yi2)单元之间有一堵不可逾越的墙。

(当中。|Xi1-Xi2|+|Yi1-Yi2|=1。0<=Gi<=P)

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

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

(当中1<=Qi<=P)

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

输出

输出文件仅仅包括一个整数T,表示麦克营救到大兵瑞恩的最短时间的值。若不存在可行的营救方案则输出-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

參数设定

3<=N,M<=15;

1<=P<=10;

首先这个题的数据很的水。所以能够暴力过(Rivendell大神的暴力飞快),那么如何去暴力呢?

因为这道题能够往回走反复的边,直接dfs会死循环,所以我们要多记录一些东西来避免这个问题,比方经过了这个点几次之类的(当然这也得看脸。



事实上这道题的正解是分层图。这是个什么东西呢?

因为有p种钥匙,p仅仅有10,钥匙的拥有状况仅仅是2^p种。

这样我们就能够来建2^p张图。然后我们能够用二进制中的0。1来表示在这张图上的时候已经拥有了那些种钥匙,从而得知在这些图上能够走哪些路。

那么如何建图呢?

对于普通的边,我们在全部的图中都连上这种双向变。

对于须要钥匙的边。我们仅仅在二进制表示的图中有对应钥匙的图上连上这些边(也就是二进制中对应的位上为1的那些边)。

对于有钥匙的点,增加有钥匙i,那么我们要在两个图之间连一条单向边,如何的两个图呢?事实上就是二进制上仅仅有第i位不同的,从第i位为0的向第i位为1的连单向边。

然后从第一张图的左上角到最后一张图的右下角跑最短路,然后在全部的图中的到右下角的路径长度中选取最小值就能够了。

事实上这种思路跟dp有些类似

暴力:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define inf 210000000
int n,m,p,K,S,map[16][16][16][16],ans,own[11]={0},use[16][16]={0};
int xi[4]={-1,0,0,1},yi[4]={0,-1,1,0};
bool key[16][16][11]={0};
void dfs(int x,int y,int z,int lx,int ly)
{
int i,j,xx,yy;
bool ff=false;
if(x==n&&y==m){
ans=min(ans,z);
return ;
}
if((use[x][y]>5)||(z+n+m-x-y>=ans)) return ;
for(i=1;i<=p;++i)
if(key[x][y][i]){
own[i]+=1;
ff=true;
}
for(i=0;i<=3;++i){
xx=x+xi[i];yy=y+yi[i];
if(xx==lx&&yy==ly&&!ff) continue;
if(xx>0&&xx<=n&&yy>0&&yy<=m){
if(map[x][y][xx][yy]<0||own[map[x][y][xx][yy]]){
use[xx][yy]+=1;
dfs(xx,yy,z+1,x,y);
use[xx][yy]-=1;
}
}
}
for(i=1;i<=p;++i)
if(key[x][y][i])
own[i]-=1;
}
int main()
{
freopen("rescue.in","r",stdin);
freopen("rescue.out","w",stdout);
int i,j,x1,y1,x2,y2,x,y,z;
scanf("%d%d%d%d",&n,&m,&p,&K);
memset(map,128,sizeof(map));
for(i=1;i<=K;++i){
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&z);
map[x1][y1][x2][y2]=map[x2][y2][x1][y1]=z;
}
scanf("%d",&S);
for(i=1;i<=S;++i){
scanf("%d%d%d",&x,&y,&z);
key[x][y][z]=true;
}
ans=inf;
dfs(1,1,0,0,0);
ans=(ans==inf? -1:ans);
printf("%d\n",ans);
}

分层图:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define inf 210000000LL
const int N=300000;
int n,m,p,K,S,ans,tot=1,point[N],next[N*5],dis[N],l[1000000];
int map[16][16][16][16],key[16][16][11],pow[2000];
int xi[4]={-1,0,0,1},yi[4]={0,-1,1,0};
struct A{int st,en,va;}aa[N*5];
struct C{int a[11];}c[1200];
bool f[N];
void add(int x,int y,int z)
{
tot+=1;next[tot]=point[x];point[x]=tot;
aa[tot].st=x;aa[tot].en=y;aa[tot].va=z;
}
void change(int x)
{
int t=x;
memset(c[x].a,0,sizeof(c[x].a));
while(t){
c[x].a[++c[x].a[0]]=t%2;
t/=2;
}
}
int get_line(int x,int y)
{
int i,out=0;
for(i=1;i<=p;++i){
if(i==y) out+=pow[i-1]*(c[x].a[i]==0?1:0);
else out+=pow[i-1]*c[x].a[i];
}
return out;
}
void SPFA(int x)
{
int i,u,h=1,t=1;
memset(f,1,sizeof(f));
memset(dis,127/3,sizeof(dis));
l[h]=x;dis[x]=0;
while(h<=t){
u=l[h];
f[u]=true;
for(i=point[u];i;i=next[i])
if(dis[aa[i].en]>dis[u]+aa[i].va){
dis[aa[i].en]=dis[u]+aa[i].va;
if(f[aa[i].en]){
f[aa[i].en]=false;
t+=1;
l[t]=aa[i].en;
}
}
h+=1;
}
}
int main()
{
freopen("rescue.in","r",stdin);
freopen("rescue.out","w",stdout);
int i,j,k,l,x1,y1,x2,y2,x,y,z;
scanf("%d%d%d%d",&n,&m,&p,&K);
memset(map,128,sizeof(map));
pow[0]=1;
for(i=1;i<=10;++i) pow[i]=pow[i-1]*2;
for(i=1;i<=pow[p];++i) change(i);
memset(c[0].a,0,sizeof(c[0].a));
for(i=1;i<=K;++i){
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&z);
map[x1][y1][x2][y2]=map[x2][y2][x1][y1]=z;
}
scanf("%d",&S);
for(i=1;i<=S;++i){
scanf("%d%d%d",&x,&y,&z);
for(j=0;j<pow[p];++j)
if(!c[j].a[z]){
int t=get_line(j,z);
add((x-1)*m+y+j*n*m,(x-1)*m+y+t*n*m,0);
}
}
for(i=1;i<=n;++i)
for(j=1;j<=m;++j)
for(k=0;k<=3;++k){
x=i+xi[k];y=j+yi[k];
if(x>0&&x<=n&&y>0&&y<=m){
if(map[i][j][x][y]<0)
for(l=0;l<pow[p];++l)
add((i-1)*m+j+l*n*m,(x-1)*m+y+l*n*m,1);
if(map[i][j][x][y]>=1)
for(l=0;l<pow[p];++l)
if(c[l].a[map[i][j][x][y]])
add((i-1)*m+j+l*n*m,(x-1)*m+y+l*n*m,1);
}
}
ans=inf;
SPFA(1);
for(i=1;i<=pow[p];++i)
ans=min(ans,dis[n*m*i]);
ans=(ans==inf? -1:ans);
printf("%d\n",ans);
}

【CTSC1999】【解救大兵瑞恩】的更多相关文章

  1. 以&quot;小刀会“的成败论当今创业成败

    讲起"小刀会",熟悉的人或许非常熟悉,不熟悉的人或许根本不知道清末有这样一个组织. 依据翻查史料,最初的小刀会是在福建成立的,来源有两个.一个是天地会的分支,一个是白莲教分支. 而 ...

  2. COJ 拯救瑞恩

    试题描述 在n行n列的字符方阵中I表示“我”最初所在位置,R是大兵瑞恩所在位置.4<n<11.“我”从当前位置可以向上.或下.或左.或右移动一格,只要新点无障碍且未出界.标有“.”的位置可 ...

  3. HDU4845(SummerTrainingDay02-C 状态压缩bfs)

    拯救大兵瑞恩 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Subm ...

  4. hdu 4845 状压bfs(分层思想)

    拯救大兵瑞恩 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Subm ...

  5. 【网络流24题】 No.14 孤岛营救问题 (分层图最短路)

    [题意] 1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛, 营救被敌军俘虏的大兵瑞恩. 瑞恩被关押在一个迷宫里, 迷宫地形复杂, 但幸好麦克得到了迷宫的地形图. 迷宫的外形是 ...

  6. [CTSC 1999]拯救大兵瑞恩&[网络流24题]孤岛营救问题

    Description $1944$ 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫 ...

  7. 【codevs 1911 孤岛营救问题】

    ·为了分析方便,可以先做一个题目简化.去掉"钥匙"这个条件,那么就是一个BFS或者SPFA--现在加上该条件.如本题只给出最多两种钥匙,当然你可以继续坚持BFS等方式,时间不会太差 ...

  8. Python开发爬虫之静态网页抓取篇:爬取“豆瓣电影 Top 250”电影数据

    所谓静态页面是指纯粹的HTML格式的页面,这样的页面在浏览器中展示的内容都在HTML源码中. 目标:爬取豆瓣电影TOP250的所有电影名称,网址为:https://movie.douban.com/t ...

  9. pydemo_testMaopuSpider

    import json from multiprocessing import Pool import requests from requests.exceptions import Request ...

随机推荐

  1. VB.NET让webbrowser控件中JS脚本错误最新方法(2013-09-16)

    最近也是在项目中遇到了webbrowser控件中想关闭JS脚本错误窗口的问题,所以经过多次测试,终于用一段高效实用的代码完美解决webbrowser控件中JS脚本错误窗口关闭的问题. 通过创建一个子线 ...

  2. 云服务和虚拟机的预留 IP 地址

    大家好! 我很高兴地向大家宣布,云服务和虚拟机的预留 IP 地址将自 2014年 5月 12日起正式发布.在这篇博客中,我们将演示如何管理预留 IP.将预留 IP 与云服务和虚拟机关联.定价模型和一些 ...

  3. kernal linear regression

  4. Android Activity 启动模式详解

    最近有群里的朋友问我 Activity的四种启动模式分别是什么意思? 当初因为项目比较忙,草草的解释了下, Api文档中说的也只是一般,在这里就小记一下吧,以便有更多的朋友对Activity启动模式了 ...

  5. 【Leetcode】Set Matrix Zeroes

    给定一个m x n的矩阵,如果某个元素为0,则把该元素所在行和列全部置0. Given a m x n matrix, if an element is 0, set its entire row a ...

  6. JAVA策略模式

    <JAVA与模式>之策略模式 在阎宏博士的<JAVA与模式>一书中开头是这样描述策略(Strategy)模式的: 策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法 ...

  7. CLR via C# 阅读笔记

    1.char在C#中为16位Unicode字符:int 映射到System.Int32;long映射到System.Int64. 2.重载时C#不考虑返回值,而CLR允许返回值不同,方法名和参数相同的 ...

  8. jQuery源码笔记——四

    each()实现 var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ) ...

  9. Android : Activity 和 TabActivity 共用一个OptionMenu

    在虚拟机上我可以用menu键打开OptionMenu,但是到了真机上没有menu键了.OptionMenu没有办法打开,所以只能采用google推荐到ActionBar.用右上角到三个点代替实体到me ...

  10. FPGA开发(2)

    1. 通常SPI通信的验证流程: 2. 对于主机而言,这里的FPGA为从机,而我们最关心SPI_CS,SPI_CSK,SPI_MISI这三个信号.SPI_CS为片选使能端,片选有效时FPGA才可以接受 ...