1152. 简单的马周游问题
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge
Description
在一个5 * 6的棋盘中的某个位置有一只马,如果它走29步正好经过除起点外的其他位置各一次,这样一种走法则称马的周游路线,试设计一个算法,从给定的起点出发,找出它的一条周游路线。
为了便于表示一个棋盘,我们按照从上到下,从左到右对棋盘的方格编号,如下所示:
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
25 26 27 28 29 30
马的走法是“日”字形路线,例如当马在位置 15 的时候,它可以到达 2 、 4 、 7 、 11 、 19 、 23 、 26 和 28 。但是规定马是不能跳出棋盘外的,例如从位置 1 只能到达 9 和 14 。
Input
输入有若干行。每行一个整数N(1<=N<=30),表示马的起点。最后一行用-1表示结束,不用处理。
Output
对输入的每一个起点,求一条周游线路。对应地输出一行,有30个整数,从起点开始按顺序给出马每次经过的棋盘方格的编号。相邻的数字用一个空格分开。
Sample Input
4 -1
Sample Output
注意:如果起点和输入给定的不同,重复多次经过同一方格或者有的方格没有被经过,都会被认为是错误的。
Problem Source
ZSUACM Team Member
跟1153差不多,数据规模小了,可以去看看我的那篇,这里不做多陈述了:
很久之前做的:0.4s,没有优化的DFS:
#include <stdio.h>
#include <string.h>
int h[6][7], st[31], now, go[] = {-2, -1, -2, 1, -1, 2, 1, 2, 2, 1, 2, -1, 1, -2, -1, -2};
void horse(int i, int j, int now) {
int goi, goj;
h[i][j] = 1;
st[now] = i * 6 + j + 1;
if (now == 29)
return;
for (int k = 0; k < 16; k += 2) {
goi = i + go[k];
goj = j + go[k + 1];
if (goi >= 0 && goi <= 4 && goj >= 0 && goj <= 5 && h[goi][goj] == 0)
horse(goi, goj, now + 1);
}
if (st[now + 1] == 0) {
st[now] = 0;
h[i][j] = 0;
}
return;
}
int main() {
int n, i, j;
while (scanf("%d", &n), n != -1) {
now = 0;
memset(h, 0, sizeof(h));
memset(st, 0, sizeof(st));
i = (n - 1) / 6;
j = (n - 1) % 6;
horse(i, j, now);
printf("%d", st[0]);
for (i = 1; i < 30; i++)
printf(" %d", st[i]);
printf("\n");
}
return 0;
}
然后做了1153之后回头重做此题:0s:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
using namespace std;
bool is_ok;
int mapp[5][6];
bool vis[5][6];
int ans[30];
int dir[8][2] = {-2,1,-1,2,1,2,2,1,2,-1,1,-2,-1,-2,-2,-1};
void make_map() {
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 6; j++) {
mapp[i][j] = i * 6 + j + 1;
}
}
}
bool is_valid(int i, int j) {
if (i < 0 || j < 0 || i > 4 || j > 5 || vis[i][j]) {
return false;
}
return true;
}
int cal_roads(int ii, int jj) {//计算下一步有多少条路可以走
int counter = 0;
for (int i = 0; i < 8; i++) {
int next_i = ii + dir[i][0];
int next_j = jj + dir[i][1];
if (is_valid(next_i, next_j)) {
counter++;
}
}
return counter;
}
struct choose {
int ii;
int jj;
int roads;
choose() {}
choose(int i, int j) {
ii = i;
jj = j;
roads = cal_roads(i, j);
}
};
bool cmp(choose a, choose b) {
return a.roads < b.roads;
}
void DFS(int from_i, int from_j, int num) {
vector<choose> cho;
for (int i = 0; i < 8; i++) {
int next_i = from_i + dir[i][0];
int next_j = from_j + dir[i][1];
if (is_valid(next_i, next_j)) {
cho.push_back(choose(next_i, next_j));
}
}
if (cho.empty())//这里千万注意,我忘记了没有路的时候是要返回的,弄了一个下午。。
return;
sort(cho.begin(), cho.end(), cmp);
if (num == 29) {
ans[num] = mapp[cho[0].ii][cho[0].jj];
is_ok = true;
return;
}
for (int i = 0; i < (int)cho.size(); i++) {
vis[cho[i].ii][cho[i].jj] = true;
DFS(cho[i].ii, cho[i].jj, num + 1);
if (is_ok) {
ans[num] = mapp[cho[i].ii][cho[i].jj];
return;
} else {
vis[cho[i].ii][cho[i].jj] = false;
}
}
}
int main() {
int sp;
make_map();
while (scanf("%d", &sp) && sp != -1) {
memset(vis, false, sizeof(vis));
vis[(sp - 1) / 6][(sp - 1) % 6] = true;
memset(ans, 0, sizeof(ans));
ans[0] = sp;
is_ok = false;
DFS((sp - 1) / 6, (sp - 1) % 6, 1);
for (int i = 0; i < 30; i++) {
if (i != 0)
printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
return 0;
}
之后发现一个很好玩的现象,其实我自己编了个程序来找,结果找到了成环的路:
于是乎。。
#include <stdio.h>
int main(){int r[60]={1,14,25,21,29,18,5,16,27,19,8,4,12,23,10,6,17,30,22,26,13,2,15,28,24,11,3,7,20,9},n,i=30;while(i<60)r[i++]=r[i-30];while(scanf("%d",&n)&&n+1)for(i=0;i<30;i++)if(n==r[i]){printf("%d",n);while(r[++i]-n)printf(" %d",r[i]);printf("\n");}return 0;}
好吧我有病。。