• 「NOIP2013」华容道


    传送门
    Luogu

    解题思路

    预支一点东西:
    这题其实有着更为思维的图模型,还十分考验码力,不简单啊 这居然是联赛题
    讲正解:
    显然我们对于一种合法方案,空格子肯定是一直围绕着特定棋子反复横跳的。
    所以说我们可以先预处理一下:对于任何一种合法的情况,求出空格在指定棋子的四个方向横跳的最小步数,这个可以通过多次 ( ext{BFS}) 来求。
    然后考虑处理询问。
    不难想到任何一种走法都是先让空格来到指定棋子旁,然后进行上面提到的反复横跳,最后空格也一定会与指定棋子相邻。
    所以说,我们就对于每一种指定棋子和空格的摆放情况创建一个节点,通过空格的横跳和指定棋子和空格的交换,也就是摆放情况的变化来连边。
    每次询问时,我们先让空格来到指定棋子旁(这个需要枚举四个不同方向,当然要合法),
    然后多源最短路,最后枚举一下终止状况,取最小步数的方案作为答案就好了。
    说是这么说,其实码起来细节多得不得了啊。。。

    细节注意事项

    • 爆搜题,你们懂得。。。

    参考代码

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    #include <queue>
    #define rg register
    using namespace std;
    template < typename T > inline void read(T& s) {
    	s = 0; int f = 0; char c = getchar();
    	while (!isdigit(c)) f |= c == '-', c = getchar();
    	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    	s = f ? -s : s;
    }
    
    const int _ = 32;
    const int __ = 10005;
    const int dx[] = { -1, 0, 0, 1 };
    const int dy[] = { 0, -1, 1, 0 };
    
    int n, m, q, a[_][_];
    int f[4][_][_][_][_], vis[_][_];
    int Vis[__], dis[__];
    struct node { int x, y; } ;
    
    int tot, head[__], nxt[__ << 3], ver[__ << 3], w[__ << 3];
    inline void Add_edge(int u, int v, int d)
    { nxt[++tot] = head[u], head[u] = tot, ver[tot] = v, w[tot] = d; }
    
    inline int id(int x, int y, int t) { return (x - 1) * 120 + (y - 1) * 4 + t; }
    
    inline void calc(int sx, int sy) {
    	static queue < node > Q;
    	for (rg int k = 0; k < 4; ++k) {
    		memset(vis, -1, sizeof vis);
    		int x = sx + dx[k], y = sy + dy[k];
    		if (x < 1 || x > n || y < 1 || y > m) continue;
    		vis[x][y] = 1, f[k][sx][sy][sx][sy] = 0, Q.push((node) { sx, sy });
    		Add_edge(id(sx, sy, 3 - k), id(x, y, k), 1);
    		while (!Q.empty()) {
    			node u = Q.front(); Q.pop();
    			int x = u.x, y = u.y;
    			for (rg int t = 0; t < 4; ++t) {
    				int xx = x + dx[t], yy = y + dy[t];
    				if (xx < 1 || xx > n || yy < 1 || yy > m) continue;
    				if (vis[xx][yy] != -1 || !a[xx][yy] || (xx == sx && yy == sy)) continue;
    				f[k][sx][sy][xx][yy] = f[k][sx][sy][x][y] + 1;
    				vis[xx][yy] = 1, Q.push((node) { xx, yy });
    			}
    		}
    		for (rg int t = 0; t < 4; ++t) {
    			int xx = x + dx[t], yy = y + dy[t];
    			if (k + t == 3 || f[k][sx][sy][xx][yy] == 0x3f3f3f3f) continue;
    			Add_edge(id(sx, sy, 3 - k), id(xx, yy, t), f[k][sx][sy][xx][yy]);
    		}
    	}
    }
    
    inline void init() {
    	memset(f, 0x3f, sizeof f);
    	for (rg int i = 1; i <= n; ++i)
    		for (rg int j = 1; j <= m; ++j)
    			if (a[i][j]) calc(i, j);
    }
    
    inline void bfs(int ex, int ey, int sx, int sy) {
    	static queue < node > Q;
    	Q.push((node) { ex, ey });
    	vis[ex][ey] = 0;
    	while (!Q.empty()) {
    		node u = Q.front(); Q.pop();
    		int x = u.x, y = u.y;
    		for (rg int k = 0; k < 4; ++k) {
    			int xx = x + dx[k], yy = y + dy[k];
    			if (xx < 1 || xx > n || yy < 1 || yy > m) continue;
    			if (!a[xx][yy] || vis[xx][yy] != -1 || (xx == sx && yy == sy)) continue;
    			vis[xx][yy] = vis[x][y] + 1, Q.push((node) { xx, yy });
    		}
    	}
    }
    
    inline void Dijkstra(int sx, int sy) {
    	static priority_queue < pair < int, int > > Q;
    	for (rg int k = 0; k < 4; ++k) {
    		int xx = sx + dx[k], yy = sy + dy[k];
    		if (xx < 1 || xx > n || yy < 1 || yy > m || !a[xx][yy]) continue;
    		int ID = id(xx, yy, k);
    		dis[ID] = vis[xx][yy] == -1 ? 0x3f3f3f3f : vis[xx][yy];
    		Q.push(make_pair(-dis[ID], ID));
    	}
    	while (!Q.empty()) {
    		int u = Q.top().second; Q.pop();
    		if (Vis[u]) continue; Vis[u] = 1;
    		for (rg int i = head[u]; i; i = nxt[i]) {
    			int v = ver[i];
    			if (dis[v] > dis[u] + w[i])
    				dis[v] = dis[u] + w[i], Q.push(make_pair(-dis[v], v));
    		}
    	}
    }
    
    inline void solve() {
    	memset(Vis, 0, sizeof Vis);
    	memset(vis, -1, sizeof vis);
    	memset(dis, 0x3f, sizeof dis);
    	int ex, ey, sx, sy, tx, ty;
    	read(ex), read(ey), read(sx), read(sy), read(tx), read(ty);
    	if (sx == tx && sy == ty) { puts("0"); return ; }
    	bfs(ex, ey, sx, sy), Dijkstra(sx, sy);
    	int ans = 0x3f3f3f3f;
    	for (rg int i = 0; i < 4; ++i) {
    		int x = tx + dx[i], y = ty + dy[i];
    		if (x < 1 || x > n || y < 1 || y > m) continue;
    		ans = min(ans, dis[id(x, y, i)]);
    	}
    	if (ans == 0x3f3f3f3f) puts("-1"); else printf("%d
    ", ans);
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
     	freopen("in.in", "r", stdin);
    #endif
    	read(n), read(m), read(q);
    	for (rg int i = 1; i <= n; ++i)
    		for (rg int j = 1; j <= m; ++j) read(a[i][j]);
    	init();
    	while (q--) solve();
    	return 0;
    }
    

    完结撒花 (qwq)

  • 相关阅读:
    无限级分类表设计
    多表连接
    连接(上接子查询那一篇随笔)
    数据库中常用指令
    子查询
    mysql查询表达式解析
    mysql单表删除记录DELETE
    mysql 单表更新记录UPDATE
    七言
    时分秒计算案例
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/11771625.html
Copyright © 2020-2023  润新知