老曹骑士(bfs)

老曹骑士

题目大意

给你一个网格,然后有一些点要走,问你从一个要走的出发走过所有要走的点在回到你出发的点。
要用的最小步数,而且每次走是像象棋的马一样走“日”字形。

思路

你看到范围,不难想到其实可以直接 bfs。
状态就是 f x , y , s , z f_{x,y,s,z} fx,y,s,z​ 表示当前走到 ( x , y ) (x,y) (x,y) 的位置,你是从第 s s s 个要走的点出发的,然后当前要走的点你走的状态时 z z z。(第 i i i 位表示第 i i i 个你要走的点走或没走)

然后就正常跑 bfs,如果当前的状态 ( x , y ) (x,y) (x,y) 就是第 s s s 个要走的点而且 z = 2 k − 1 z=2^k-1 z=2k−1(即所有要走的点都走到了),那就可以作为结束的状态了。
然后就可以啦。

代码

#include<queue> 
#include<cstdio>
#include<cstring>
#define ll long long

using namespace std;

int n, k, xx[11], yy[11], x, y, s, z;
int f[21][21][10][1024], ans;
int dx[8] = {-1, -2, -2, -1, 1, 2, 2, 1};//日字形
int dy[8] = {-2, -1, 1, 2, 2, 1, -1, -2};
int hx[21][21];
bool go[21][21][10][1024];
struct zt {
	int x, y, s, z;
};
queue <zt> q;

bool in(int x, int y) {
	if (x < 1 || x > n) return 0;
	if (y < 1 || y > n) return 0;
	return 1;
}

int main() {
	memset(f, 0x7f, sizeof(f));
	
	scanf("%d %d", &n, &k);
	for (int i = 0; i < k; i++) {
		scanf("%d %d", &xx[i], &yy[i]);
		f[xx[i]][yy[i]][i][1 << i] = 0;
		q.push((zt){xx[i], yy[i], i, (1 << i)});
		hx[xx[i]][yy[i]] = i + 1;
	}
	
	ans = 2e9;
	while (!q.empty()) {
		x = q.front().x; y = q.front().y; s = q.front().s; z = q.front().z;
		q.pop();
		if (go[x][y][s][z]) continue;
		go[x][y][s][z] = 1;
		
		if (x == xx[s] && y == yy[s] && z == (1 << k) - 1) {//走完了
			ans = min(ans, f[x][y][s][z]);
			continue;
		}
		for (int i = 0; i < 8; i++) {
			int tx = x + dx[i], ty = y + dy[i];
			if (!in(tx, ty)) continue;
			int tz = z;
			if (hx[tx][ty]) {//走到一个要走的点
				tz |= (1 << (hx[tx][ty] - 1));
			}
			if (f[x][y][s][z] + 1 < f[tx][ty][s][tz]) {
				f[tx][ty][s][tz] = f[x][y][s][z] + 1;
				q.push((zt){tx, ty, s, tz});
			}
		}
	}
	
	printf("%d", ans);
	
	return 0;
}
上一篇:C++基本类的两种c++11写法


下一篇:uart write example