[SPFA]JZOJ 5781 秘密通道

Description

有一副n*m的地图,有n*m块地,每块是下列四种中的一种:
墙:用#表示,墙有4个面,分别是前面,后面,左面,右面。
起点:用C表示,为主角的起点,是一片空地。
终点:用F表示,为主角的目的地,是一片空地。
空地:用 . 表示。
其中除了墙不能穿过,其他地方都能走。
 
主角有以下3种操作:
1.移动到相邻的前后左右的地方,花费一个单位时间。
2.向前后左右其中一个方向发射子弹,子弹沿直线穿过,打在最近的一堵墙的一面,然后墙的这面就会形成一个开口通往秘密通道。同一时间最多只能有两个开口,若出现有3个开口,出现时间最早的开口会立即消失。该操作不用时间。
3.可以从一个与开口相邻的空地跳进去,进入秘密通道,从另外一个开口正对的空地跳出来。这个过程花费一个单位时间。

地图四周都是墙,问主角最少用多少时间从C走到F。C和F
只会出现一次。

Input

第一行输入两个正整数n,m。
接下来n行,每行m个字符描述地图。

Output

输出1个整数,表示最短时间完成路途。如果无解输出nemoguce

Sample Input

Input 1
4 4
####
#.F#
#C.#
####
Input 2
6 8
########
#.##..F#
#C.##..#
#..#...#
#.....##
########
Input 3
4 5
#####
#C#.#
###F#
#####
 

Sample Output

Output 1
2
Output 2
4
Output 3
nemoguce

Data Constraint

对于50%的数据,4≤ n,m≤ 15。
对于100%的数据,4≤ n,m≤ 500。

Hint

总共用到8次操作,时间之和为4。如下图所示
1.向左射一枪,在(3,1)的右面出现开口。
2.向下射一枪,在(6,2)的上面出现开口。
3.向左从(3,1)进入秘密通道,从(6,2)中出来,到达(5,2)。用1单位时间。
4.向右射一枪,在(5,7)的左面出现开口,(3,1)右面的开口消失。
5.走进(6,2)的开口,出来到(5,6)。用1单位时间。
6.向上射一枪,在(1,6)的下面出现开口。
7.经过秘密通道,走到(2,6)。用1单位时间。
8.走到终点。用1单位时间。

分析

显然我们可以贪心:在一个点,我们到达其他墙面前的距离=min(dis直接走,dis到最近墙的距离+传送花费时间)

然后就是建一波边,跑SPFA

(其实这题是最难的= =)

#include <iostream>
#include <cstdio>
#include <memory.h>
#include <queue>
using namespace std;
const int N=501;
struct Edge {
    int u,v,w,nx;
}g[8*N*N];
int cnt,list[N*N];
struct Point {
    int x,y;
}st,ed;
char c[N][N];
int f[N][N],dis[N*N];
bool b[N][N],vis[N*N];
int n,m;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};

Point P (int x,int y) {
    Point p;p.x=x;p.y=y;return p;
}
bool Check(Point p) {
    return p.x>=0&&p.y>=0&&p.x<n&&p.y<m&&c[p.x][p.y]!=‘#‘&&!b[p.x][p.y];
}

void Add(int u,int v,int w) {
    g[++cnt].u=u;g[cnt].v=v;g[cnt].w=w;g[cnt].nx=list[u];list[u]=cnt;
}

void Init() {
    scanf("%d%d",&n,&m);
    for (int i=0;i<n;i++)
    for (int j=0;j<m;j++) {
        do {
            scanf("%c",&c[i][j]);
        }
        while (c[i][j]!=‘#‘&&c[i][j]!=‘.‘&&c[i][j]!=‘C‘&&c[i][j]!=‘F‘);
        if (c[i][j]==‘C‘) st.x=i,st.y=j;
        if (c[i][j]==‘F‘) ed.x=i,ed.y=j;
    }
}

void Pre_Process() {
    for (int i=0;i<n;i++)
    for (int j=0;j<m;j++)
    if (c[i][j]!=‘#‘) f[i][j]=f[i][j-1]+1;
    int x;
    for (int i=0;i<n;i++)
    for (int j=m;j>=0;j--)
    if (c[i][j]!=‘#‘) f[i][j]=min(f[i][j],x+1),x++;
    else x=0;
    for (int j=0;j<m;j++)
    for (int i=0;i<n;i++)
    if (c[i][j]!=‘#‘) f[i][j]=min(f[i][j],x+1),x++;
    else x=0;
    for (int j=0;j<m;j++)
    for (int i=n;i>=0;i--)
    if (c[i][j]!=‘#‘) f[i][j]=min(f[i][j],x+1),x++;
    else x=0;
    for (int i=0;i<n;i++)
    for (int j=0;j<m;j++)
    if (Check(P(i,j)))
    for (int k=0;k<4;k++) {
        Point p=P(i,j);
        while (Check(p)) {
            p.x+=dx[k];p.y+=dy[k];
        }
        p.x-=dx[k];p.y-=dy[k];
        Add(i*m+j,p.x*m+p.y,f[i][j]);
        if (Check(P(i+dx[k],j+dy[k]))) Add(i*m+j,(i+dx[k])*m+j+dy[k],1);
    }
}

void Spfa() {
    queue <int> q;
    while (!q.empty()) q.pop();
    memset(dis,0x3f,sizeof dis);
    q.push(st.x*m+st.y);vis[st.x*m+st.y]=1;dis[st.x*m+st.y]=0;
    while (!q.empty()) {
        int u=q.front();q.pop();
        for (int i=list[u];i;i=g[i].nx)
        if (dis[u]+g[i].w<dis[g[i].v]) {
            dis[g[i].v]=dis[u]+g[i].w;
            if (!vis[g[i].v]) q.push(g[i].v);
            vis[g[i].v]=1;
        }
        vis[u]=0;
    }
}

int main() {
    freopen("portal.in","r",stdin);
    freopen("portal.out","w",stdout);
    Init();
    Pre_Process();
    Spfa();
    if (dis[ed.x*m+ed.y]==1061109567) printf("nemoguce");
    else printf("%d",dis[ed.x*m+ed.y]);
    fclose(stdin);fclose(stdout);
}

原文地址:https://www.cnblogs.com/mastervan/p/9445456.html

时间: 2024-08-03 09:07:46

[SPFA]JZOJ 5781 秘密通道的相关文章

[spfa] Jzoj P4722 跳楼机

Description DJL为了避免成为一只咸鱼,来找srwudi学习压代码的技巧.Srwudi的家是一幢h层的摩天大楼.由于前来学习的蒟蒻越来越多,srwudi改造了一个跳楼机,使得访客可以更方便的上楼.经过改造,srwudi的跳楼机可以采用以下四种方式移动:1.向上移动x层:2.向上移动y层:3.向上移动z层:4.回到第一层.一个月黑风高的大中午,DJL来到了srwudi的家,现在他在srwudi家的第一层,碰巧跳楼机也在第一层.DJL想知道,他可以乘坐跳楼机前往的楼层数. Input 第

李欣频经典文案整理(一)

https://www.douban.com/note/268353360/?type=like 海明威阅读海,发现生命是一条要花一辈子才会上勾的鱼.凡高阅读麦田,发现艺术躲在太阳的背后乘凉.弗洛伊德阅读梦,发现一条直达潜意识的秘密通道.罗丹阅读人体,发现哥伦布没有发现的美丽海岸线.加缪阅读卡夫卡,发现真理已经被讲完一半.在书与非书之间,我们欢迎各种可能的阅读者.                                                       ————进入诚品之门的文

震惊:2/3 被黑的网站隐藏着后门

导读 网络安全公司 Sucuri 的安全专家表示,他们在调查中发现有 68% 的被黑网站存在着隐藏的后门backdoor脚本.这些后门脚本会给入侵者提供再次进入秘密通道,即便系统管理员改变了口令或应用了安全补丁,只要没有完全的清理整个系统,后门就会依旧存在. 从他们发布的网站被黑报告 2016 Q1 版中可以看到,全部取样的 11485 个网站中有 4900 个网站发现了后门,在这些被入侵的网站中,后门是最严重的问题,其次是恶意代码(通过浏览器端的代码进行挂马攻击),占比 60%.第三名是SEO

堪称最好的A*算法

如此好贴,不能不转!原文地址:http://dev.gameres.com/Program/Abstract/Arithmetic/AmitAStar.mht 本文版权归原作者.译者所有,我只是转贴:如果侵害到您的权益,请联系我,我将删除本文. 基本上,这文章可以说是最佳A*算法文档.极力推荐! Amit's A star Page中译文   译序 这篇文章很适合A*算法的初学者,可惜网上没找到翻译版的.本着好东西不敢独享的想法,也为了锻炼一下英文,本人译了这篇文章. 由于本人英文水平非常有限,

圳沿苁贤子mn43eita

笑红尘失笑道:"你信吗?"听着内院学长们的介绍,霍雨浩认真的将他们的名字.擅长.魂力等级都记在心中.虽然他们只是辅助参赛,但把这些都记清显然是有好处的.星罗帝国皇帝许家伟本来是想要邀请玄老进入皇家宝库选择的,却被玄老拒绝了,他老人家作为对外的史莱克学院第一强者,不愿和星罗帝国牵扯上未多的关系.最终还是王言代表学院进行选择.他对于队员足够了解,对于魂骨的辨别能力,也决不在玄老之下.和菜头的身材在史莱克七怪中是最为庞大的一个,而萧萧则是最为娇小的一个.此时此刻,让这么一个小姑娘挡在自己前面

弹丸论破2 中文攻略

最近在推这个游戏,于是转一篇自己看着比较顺眼的攻略= = -------------------------------------------------------------------------- 转载请注明作者和出处 [email protected]洛天之痕 写在前面: 虽然弹丸2感觉还是自己打通的比较有成就感啦,但苦逼的撸主在打完一周目后发现还有那么多CG和隐藏熊币没拿确实很蛋疼(残缺的男人无幸福啊,我的福利),所以为了广大同胞们第一次玩的幸福点(撸主第一个反论钻研了半个多小时.

管理之道(十四) - 如何留住员工

又马上要到一年的金三银四,新一轮求职大潮又来临了.许多中小软件企业每年的这个时候都在担心员工的流失,但对此又无可奈何.无法提供优厚的待遇,良好的发展空间,不知道开发人员到底想要什么,整天还要做各种适得其反的错误行为,员工不流失反而会奇怪了. 留住员工的关键-培养员工的忠诚感.       森林之王老虎的家里,养了很多鸡.但令老虎头痛的是,由于鸡舍不牢固,鸡每天都会丢失.老虎听说狐狸聪明,于是就请狐狸来为它设计一个世界上最牢固的鸡舍.狐狸高高兴兴地上任了,并终于不负老虎的重望,建立了一个集漂亮与实

A*算法学习。

A*启发式搜索算法详解 人工智能 1导言 1.1 算法 1.2 Dijkstra算法与最佳优先搜索 1.3 A*算法 2 启发式算法 2.1 A*对启发式函数的使用 2.2 速度还是精确度? 2.3 衡量单位 2.4 精确的启发式函数 2.4.1 预计算的精确启发式函数 2.4.2 线性精确启发式算法 2.5 网格地图中的启发式算法 2.5.1 曼哈顿距离 2.5.2 对角线距离 2.5.3 欧几里得距离 2.5.4 平方后的欧几里得距离 2.5.5 Breaking ties 2.5.6 区域

黑魔法来了,不要眨眼

Clang Attributes 黑魔法小记 Clang Attributes 是 Clang 提供的一种源码注解,方便开发者向编译器表达某种要求,参与控制如 Static Analyzer.Name Mangling.Code Generation 等过程,一般以 __attribute__(xxx) 的形式出现在代码中:为方便使用,一些常用属性也被 Cocoa 定义成宏,比如在系统头文件中经常出现的 NS_CLASS_AVAILABLE_IOS(9_0) 就是 __attribute__(a