zoukankan      html  css  js  c++  java
  • 【CodeVS 3290】【NOIP 2013】华容道

    http://codevs.cn/problem/3290/

    据说2013年的noip非常难,但Purpleslz学长还是AK了。能A掉这道题真心orz。

    设状态$(i,j,k)$表示目标棋子在$(i,j)$这个位置,空格在紧贴着目标棋子的$k$方向,$0≤k<4$。

    因为目标棋子要移动,空格肯定在它旁边。往空格的方向走一步,空格便出现在它另一边。对于这两个状态连边,边权为1。

    为了使目标棋子向某一方向移动,需要目标棋子不动,空格从紧贴着目标棋子的某一方向移动到紧贴着目标棋子的另一个方向。对于固定目标棋子位置但空格对于目标棋子的方向不同的状态之间互相连边,边权需要bfs求得。

    对于每个询问,给出初始空格的位置,bfs出初始的空格移动到目标棋子旁边四个位置的最短距离,并连边, 边权为最短距离。

    最后跑spfa求出到达目标棋子到达终点需要走的最短路。

    时间复杂度$O(nm)$,因为边数是nmk级别的,而且k是个常数,所以把k忽略掉233 _(:з」∠)_k都快比nm大了QwQ

    话说spfa的复杂度真的是$O(E)$的吗(/"≡ _ ≡)/~┴┴

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N = 33;
    const int dx[4] = {-1, 0, 1, 0};
    const int dy[4] = {0, 1, 0, -1};
    int in() {
    	int k = 0, fh = 1; char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar())
    		if (c == '-') fh = -1;
    	for(; c >= '0' && c <= '9'; c = getchar())
    		k = (k << 3) + (k << 1) + c - '0';
    	return k * fh;
    }
    
    struct node {int nxt, to, w;} E[20003];
    int Move[33][33][4][4], point[4003], cnt = 0, a[33][33], n, m, qq;
    int number[33][33][4], tot = 0;
    
    void ins(int u, int v, int w) {E[++cnt] = (node) {point[u], v, w}; point[u] = cnt;}
    
    bool can(int x, int y) {
    	return ((x >= 1) && (x <= n) && (y >= 1) && (y <= m) && (a[x][y] == 1));
    }
    
    struct Point {
    	int x, y, d;
    	Point(int _x = 0, int _y = 0, int _d = 0) : x(_x), y(_y), d(_d) {}
    	bool operator == (const Point &A) const {
    		return x == A.x && y == A.y;
    	}
    } q[1003];
    
    int cross(int x, int y, int h, int hh) {
    	Point s, t;
    	s = Point(x + dx[h], y + dy[h], 0);
    	t = Point(x + dx[hh], y + dy[hh], 0);
    	a[x][y] = 0;
    	int head = 0, tail = 1;
    	q[1] = s; a[s.x][s.y] = 1;
    	
    	Point u, v;
    	while (head != tail) {
    		u = q[++head];
    		if (u == t) break;
    		for(int d = 0; d < 4; ++d)
    			if (can(u.x + dx[d], u.y + dy[d])) {
    				v = Point(u.x + dx[d], u.y + dy[d], u.d + 1);
    				q[++tail] = v;
    				a[v.x][v.y] = 0;
    			}
    	}
    	
    	for(int i = 1; i <= tail; ++i)
    		a[q[i].x][q[i].y] = 1;
    	
    	a[x][y] = 1;
    	if (u == t)	return u.d;
    	else return 0x7fffffff;
    }
    
    void dealwith(int x, int y) {
    	int ed;
    	for(int d = 0; d < 4; ++d)
    		if (can(x + dx[d], y + dy[d]))
    			for(int dd = d + 1; dd < 4; ++dd)
    				if (can(x + dx[dd], y + dy[dd])) {
    					ed = Move[x][y][d][dd] = Move[x][y][dd][d] = cross(x, y, d, dd);
    					if (ed != 0x7fffffff) {
    						ins(number[x][y][d], number[x][y][dd], ed);
    						ins(number[x][y][dd], number[x][y][d], ed);
    					}
    				}
    }
    
    int dis(Point g, Point s, Point t) {
    	int head = 0, tail = 1;
    	s.d = 0; q[1] = s; a[s.x][s.y] = 0; a[g.x][g.y] = 0;
    	Point u, v;
    	while (head != tail) {
    		u = q[++head];
    		if (u == t) break;
    		for(int d = 0; d < 4; ++d)
    			if (can(u.x + dx[d], u.y + dy[d])) {
    				v = Point(u.x + dx[d], u.y + dy[d], u.d + 1);
    				q[++tail] = v;
    				a[v.x][v.y] = 0;
    			}
    	}
    	
    	a[g.x][g.y] = 1;
    	for(int i = 1; i <= tail; ++i)
    		a[q[i].x][q[i].y] = 1;
    	if (u == t) return u.d;
    	else return 0x7fffffff;
    }
    
    queue <int> Q;
    int dist[4003], inq[4003];
    
    void spfa(int s) {
    	memset(dist, 127, sizeof(int) * (tot + 1));
    	Q.push(s); dist[s] = 0; inq[s] = true;
    	int u;
    	while (!Q.empty()) {
    		u = Q.front(); Q.pop(); inq[u] = false;
    		for(int i = point[u]; i; i = E[i].nxt)
    			if (dist[u] + E[i].w < dist[E[i].to]) {
    				dist[E[i].to] = dist[u] + E[i].w;
    				if (!inq[E[i].to]) {
    					Q.push(E[i].to);
    					inq[E[i].to] = true;
    				}
    			}
    	}
    }
    
    int main() {
    	n = in(); m = in(); qq = in();
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    			a[i][j] = in();
    	
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    			if (a[i][j] == 1)
    				for(int d = 0; d < 4; ++d)
    					if (can(i + dx[d], j + dy[d]))
    						number[i][j][d] = ++tot;
    	
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    			if (a[i][j] == 1) dealwith(i, j);
    	
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j <= m; ++j)
    			if (a[i][j] == 1)
    				for(int d = 0; d < 4; ++d)
    					if (can(i + dx[d], j + dy[d]))
    						ins(number[i][j][d], number[i + dx[d]][j + dy[d]][(d + 2) % 4], 1);
    	
    	++tot;
    	Point e, s, t;
    	int now = cnt, ans;
    	while (qq--) {
    		e.x = in(); e.y = in(); s.x = in(); s.y = in(); t.x = in(); t.y = in();
    		if (s == t) {puts("0"); continue;}
    		cnt = now; point[tot] = 0;
    		for(int d = 0; d < 4; ++d)
    			if (can(s.x + dx[d], s.y + dy[d]))
    				ins(tot, number[s.x][s.y][d], dis(s, e, Point(s.x + dx[d], s.y + dy[d], 0)));
    		spfa(tot);
    		ans = 0x7fffffff;
    		for(int d = 0; d < 4; ++d)
    			ans = min(ans, dist[number[t.x][t.y][d]]);
    		printf("%d
    ", ans == 2139062143 ? -1 : ans);
    	}
    	
    	return 0;
    }
    

    终于A掉了。注意特判起点和终点相同

  • 相关阅读:
    数据结构-顺序表
    数据结构-概论
    社交网络图中结点的“重要性”计算 (30 分) C++解法
    面向对象程序设计--Java语言第二周编程题:有秒计时的数字时钟
    面向对象程序设计--Java语言第三周编程题:查找里程
    面向对象程序设计--Java语言第一周编程题:分数
    剑指Offer_#42_连续子数组的最大和
    vue--模态框背景不动解决方案
    redis(十七):Redis 安装,部署(WINDOWS环境下)
    redis(二十一):Redis 架构模式实现(哨兵)
  • 原文地址:https://www.cnblogs.com/abclzr/p/5813770.html
Copyright © 2011-2022 走看看