[JZOJ5781]【NOIP提高A组模拟2018.8.8】秘密通道

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单位时间。

 

 


 

 

从每个点向四边连边权为1的边,从每个点,向它四个方向上的第一个墙,连以它距离某个墙最近的距离为边权的边。

然后第一种可以直接连, 第二种可以把所有的墙入队,跑bfs。

建完边跑spfa。

然后注意边的数组开大, 要不会RE.

码农题鉴定完毕。

 


 

 

 

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
inline int read() {
    int res=0;char c=getchar();bool f=0;
    while(!isdigit(c)) {if(c=='-')f=1;c=getchar();}
    while(isdigit(c))res=(res<<3)+(res<<1)+(c^48),c=getchar();
    return f?-res:res;
}
int dx[]={0, 1, -1, 0, 0}, dy[]={0, 0, 0, 1, -1};
int n, m;
int mp[505][505], tot, id[505][505];;
int stx, sty, edx, edy;
int S, T;
struct edge {
    int nxt, to, val;
}ed[5000005];
int head[250005], cnt;
inline void add(int x, int y, int z)
{
    ed[++cnt] = (edge){head[x], y, z};
    head[x] = cnt;
}

bool ex[250005];
int dis[250005];
inline void spfa()
{
    S = id[stx][sty], T = id[edx][edy];
    memset(dis, 0x3f, sizeof dis);
    queue <int> q;
    dis[S] = 0;
    q.push(S);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();ex[x] = 0;
        for (register int i = head[x] ; i ; i = ed[i].nxt)
        {
            int to = ed[i].to;
            if (dis[to] > dis[x] + ed[i].val)
            {
                dis[to] = dis[x] + ed[i].val;
                if (!ex[to]) ex[to] = 1, q.push(to);
            }
        }
    }
}

int dd[505*505];
bool vis[505][505];

struct date {
    int x, y, stp;
};

inline void bfs()
{
    queue <date> q;
    memset(dd, 0x3f, sizeof dd);
    for (register int i = 1 ; i <= n ; i ++)
        for (register int j = 1 ; j <= m ; j ++) 
            if (mp[i][j] == 2) q.push((date){i, j, 0}), vis[i][j] = 1;
    while(!q.empty())
    {
        int x = q.front().x, y = q.front().y, tp = q.front().stp;
        q.pop();
        for (register int i = 1 ; i <= 4 ; i ++)
        {
            int tx = x + dx[i], ty = y + dy[i];
            if (tx <= 0 or tx > n or ty <= 0 or ty > m) continue;
            if (mp[tx][ty] == 2) continue;
            if (vis[tx][ty]) continue;
            dd[id[tx][ty]] = min(dd[id[tx][ty]], tp + 1);
            q.push((date){tx, ty, tp + 1});
            vis[tx][ty] = 1;
        }
    }
}

int main()
{
    freopen("portal.in", "r", stdin);
    freopen("portal.out", "w", stdout);
    n = read(), m = read();
    for (int i = 1 ; i <= n ; i ++)
    {
        for (int j = 1 ; j <= m ; j ++)
        {
            char c;
            cin >> c;
            if (c == '#') mp[i][j] = 2;
            if (c == '.') mp[i][j] = 1;
            if (c == 'C') mp[i][j] = 1, stx = i, sty = j;
            if (c == 'F') mp[i][j] = 1, edx = i, edy = j;
            id[i][j] = ++tot;
        }
    }
    //for (int i=1;i<=n;i++,puts(""))for (int j=1;j<=m;j++)printf("%d ", mp[i][j]);
    for (register int i = 1 ; i <= n ; i ++)
    {
        for (register int j = 1 ; j <= m ; j ++)
        {
            if (mp[i][j] == 2) continue;
            for (register int k = 1 ; k <= 4 ; k ++)
            {
                int tx = i + dx[k], ty = j + dy[k];
                if (tx <= 0 or tx > n or ty <= 0 or ty > m) continue;
                add(id[i][j], id[tx][ty], 1);
            }
        }
    }
    bfs();
    for (register int i = 1 ; i <= n ; i ++)
    {
        for (register int j = 1 ; j <= m ; j ++)
        {
            if (mp[i][j] == 2) continue;
        //    printf("%d %d %d\n", i, j, dd[id[i][j]]);puts("");
            int now = 0, ee[10];
            while(now <= 3) 
            {
                now++;
                int tx = i, ty = j;
                while(mp[tx][ty] != 2) 
                {
                    tx += dx[now], ty += dy[now];
                    //if (tx <= 0 or tx > n or ty <= 0 or ty > m) break;
                }
                tx -= dx[now], ty -= dy[now];
        //        printf("%d %d\n", tx, ty);
                ee[now] = id[tx][ty];
            }
        //    puts("");
            for (register int k = 1 ; k <= 4 ; k ++)
                add(id[i][j], ee[k], dd[id[i][j]]);
        }
    }
    spfa();
    if (dis[T] == 0x3f3f3f3f) return puts("nemoguce"), 0;
    printf("%d\n", dis[T]);
    return 0;
}

 

posted @ 2018-08-14 19:15  zZhBr  阅读(1226)  评论(0编辑  收藏  举报