[NOIP 2013]华容道


题目链接,我觉得这是一道好题~ 题解戳这里


首先,要移动指定棋子,必定要将空格移到它的邻近方格。

然后,我们有两个决策:

  • 将空格移至指定棋子前进方向的那一格,但不能经过指定棋子
    (否则会使指定棋子的位置发生改变)
  • 交换空格与指定棋子

按这个方式构图,跑最短路就可以了。

这个图比较稀疏,SPFA 是可以解决的 (来卡我啊)。


当然还有一个需要特殊判断的情形: 方格的起始位置与结束位置相同。

Created with Raphaël 2.1.0 Solve() S(x,y)!=T(x,y) Build_graph() & ans = SPFA() End ans = 0 yes no

时间复杂度: O((NM)2+q(NM))


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <vector>
#include <utility>
#include <stack>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>

template<class Num>void read(Num &x)
{
    char c; int flag = 1;
    while((c = getchar()) < '0' || c > '9')
        if(c == '-') flag *= -1;
    x = c - '0';
    while((c = getchar()) >= '0' && c <= '9')
        x = (x<<3) + (x<<1) + (c-'0');
    x *= flag;
}
template<class Num>void write(Num x)
{
    if(!x) {putchar('0');return;}
    if(x < 0) putchar('-'), x = -x;
    static char s[20];int sl = 0;
    while(x) s[sl++] = x%10 + '0',x /= 10;
    while(sl) putchar(s[--sl]);
}
const int maxn = 35, maxm = 35, inf = 0x3f3f3f3f, nya = -1;
const int vec[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
const int node = maxn * maxm << 2, edgenum = node << 2;

int n, m, q;
int ex, ey, sx, sy, tx, ty;
int map[maxn][maxm];

struct Edge
{
    int v, w, next;
    Edge(int v = 0,int w = 0,int next = 0):v(v), w(w), next(next){};
};
int head[node], el, _head[node], _el;
Edge edge[edgenum];

int ind, S, T;

#define index(x, y, p) (((((x) - 1)*m + ((y) - 1))<<2) + (p) + 1)
#define table(x, y) (((x) - 1)*m + (y))
#define getx(S) (((S) - 1)/m + 1)
#define gety(S) (((S) - 1)%m + 1)

void newedge(int u,int v,int w)
{
    edge[++el] = Edge(v, w, head[u]), head[u] = el; 
}
int BFS(int fx,int fy,int dx,int dy,int bx,int by)
{
    if(!map[fx][fy] || fx == bx && fy == by) return inf;
    if(!map[dx][dy] || dx == bx && dy == by) return inf;

    static int line[maxn * maxm], dist[maxn * maxm];
    int f = 0, r = 0, e, p, px, py;

    for(int i = 1; i <= n*m; i++) dist[i] = nya;

    line[r++] = table(fx, fy), dist[table(fx, fy)] = 0;

    while(f != r)
    {   
        if((e = line[f++]) == table(dx, dy)) return dist[e];

        for(int i = 0; i < 4; i++)
        {
            px = getx(e) + vec[i][0], py = gety(e) + vec[i][1];

            if(px == bx && py == by) continue;

            if(dist[p = table(px, py)] == nya && map[px][py])
                line[r++] = p, dist[p] = dist[e] + 1;
        }
    }
    return inf;
}
int SPFA()
{
    static int line[node], dist[node];
    static bool hash[node];
    int f = 0, r = 0;

    for(int i = 1; i <= ind; i++)
        dist[i] = inf, hash[i] = false;

    dist[S] = 0, line[r] = S, r = (r + 1)%node;
    hash[S] = true;

    while(f != r)
    {
        int e = line[f], p;
        f = (f + 1)%node;

        hash[e] = false;

        for(int i = head[e]; i ; i = edge[i].next)
        {
            int tmp = dist[e] + edge[i].w;
            if(tmp < dist[p = edge[i].v])
            {
                dist[p] = tmp;

                if(!hash[p])
                {
                    if(dist[p] <= dist[line[f]])
                        f = (f - 1 + node) % node, line[f] = p;
                    else
                        line[r] = p, r = (r + 1) % node;    

                    hash[p] = true;
                }
            }
        }
    }

    return dist[T] < inf ? dist[T] : nya;
}           
void prework()
{
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
        {
            if(!map[i][j]) continue;

            for(int k = 0; k < 4; k++)
            {
                if(!map[i + vec[k][0]][j + vec[k][1]]) continue;

                for(int h = 0; h < 4; h++)
                    if(k != h)
                    {
                        int cost = BFS(i + vec[k][0], j + vec[k][1], i + vec[h][0], j + vec[h][1], i, j);

                        if(cost < inf) newedge(index(i, j, k), index(i, j, h), cost);
                    }

                newedge(index(i, j, k), index(i + vec[k][0], j + vec[k][1], k ^ 1), 1);
            }
        }
    S = (n * m << 2) + 1;
    T = ind = S + 1;        

    for(int i = 1; i <= ind; i++) _head[i] = head[i];
    _el = el;   
}
void init()
{
    read(n), read(m), read(q);

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            read(map[i][j]);        
}
void solve()
{
    read(ex), read(ey);
    read(sx), read(sy), read(tx), read(ty);

    if(sx == tx && sy == ty)
    {
        puts("0");
        return;
    }

    for(int i = 1; i <= ind; i++) head[i] = _head[i];
    el = _el;   

    for(int i = 0; i < 4; i++)
    {
        int cost = BFS(ex, ey, sx + vec[i][0], sy + vec[i][1], sx, sy);

        if(cost < inf) newedge(S, index(sx, sy, i), cost);

        if(map[tx + vec[i][0]][ty + vec[i][1]])
            newedge(index(tx, ty, i), T, 0);
    }

    write(SPFA()), puts("");
}
int main()
{
#ifndef ONLINE_JUDGE    
    freopen("puzzle.in","r",stdin);
    freopen("puzzle.out","w",stdout);
#endif

    init(), prework();

    while(q--) solve();

#ifndef ONLINE_JUDGE    
    fclose(stdin);
    fclose(stdout);
#endif  
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
noip2013普及组初赛是全国信息学奥林匹克联赛的一场选拔赛。该比赛旨在选拔初学者,对编程和算法有一定基础的学生,通过比赛形式来考察他们的知识水平和解题能力。 比赛题目通常会涉及各个领域的算法和数据结构,如图论、动态规划、数论等。题目难度逐步增加,从简单的输出结果,到复杂的程序设计与代码实现,考察选手的逻辑思维和编程能力。 参赛选手需要通过自己的思考和编程实现来解决题目,同时时间也是一个重要因素。比赛中,选手需要在规定的时间内独立完成所有题目,对于复杂的题目需要迅速想出解题思路并进行编码。因此,在比赛中,选手的临场发挥和解题速度也是需要考虑的因素。 noip2013普及组初赛的结果将作为选拔阶段的一个重要依据,选出表现出色的选手进入到更高阶段的比赛,对于他们来说,这是一次展示自己实力的机会。 此外,noip2013普及组初赛,也给了参赛选手一个交流的平台。选手们可以通过比赛结交同好,相互切磋,共同进步。同时,比赛结束后,还有详细的解题分析和讲解,有助于参赛选手对自己在比赛中的不足进行反思与改进。 总之,noip2013普及组初赛是一个考察学生编程和算法能力的选拔赛,通过比赛的形式来选拔出优秀的选手。这对于参赛选手来说,是一次展示自己才华的机会,也是一个展示自己实力和提高自己能力的平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值