P1518. 两只塔姆沃斯牛

考点

  • 模拟
  • 哈希函数
  • 哈希表

题解

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <bits/stdc++.h>

using namespace std;

const int P = 11;

char arr[11][11];

unordered_map<int, bool> m;

int walk[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

struct Node
{
//dir_ 0向右,1向下,2向左,3向上
int x_, y_, dir_;
Node(int x = 0, int y = 0, int dir = 3) : x_(x), y_(y), dir_(dir) {}
} f, c;

void init()
{
for (int i = 1; i <= 10; ++i)
{
for (int j = 1; j <= 10; ++j)
{
cin >> arr[i][j];
if (arr[i][j] == 'F')
{
f.x_ = i, f.y_ = j;
}
if (arr[i][j] == 'C')
{
c.x_ = i, c.y_ = j;
}
}
}
}

int hsh()
{
return f.dir_ * pow(P, 5) + c.dir_ * pow(P, 4) +
f.x_ * pow(P, 3) + f.y_ * pow(P, 2) +
+c.x_ * P + c.y_;
}

bool valid(int x, int y)
{
return x >= 1 && x <= 10 && y >= 1 && y <= 10 && arr[x][y] != '*';
}

int chase()
{
int h, t = 0, f_x, f_y, c_x, c_y;
while (!m.count(h = hsh()) && (f.x_ != c.x_ || f.y_ != c.y_))
{
m[h] = true;
f_x = f.x_ + walk[f.dir_][0], f_y = f.y_ + walk[f.dir_][1];
c_x = c.x_ + walk[c.dir_][0], c_y = c.y_ + walk[c.dir_][1];
if (!valid(f_x, f_y))
{
f.dir_ = (f.dir_ + 1) % 4;
}
else
{
f.x_ = f_x, f.y_ = f_y;
}
if (!valid(c_x, c_y))
{
c.dir_ = (c.dir_ + 1) % 4;
}
else
{
c.x_ = c_x, c.y_ = c_y;
}
++t;
}
return (f.x_ == c.x_ && f.y_ == c.y_ ? t : 0);
}

int main()
{
init();
cout << chase();
return 0;
}

思路

本题唯一的难点就在于如何确定系统的临界状态,从而跳出死循环

人与牛如果不可能碰面,即出现死循环现象,那么某一时刻的系统状态一定会出现两次

类比绕着圆形田径场一直慢跑,某路段一定会至少跑过两次

本题的系统状态是由人的横纵坐标、人的方向、牛的横纵坐标和牛的方向六个因素决定,如何记录它们呢?

采用字符串哈希类似的做法,用一个多项式将六个因素串起来作为哈希值,并在多项式内用幂次来代表影响因子的权重

在本题中,人与牛的方向是最能影响系统状态的,所以人与牛的方向这两个影响因子的幂次应该最高

由于只有100个坐标,假若将人、牛的坐标作为高权重的影响因子,极其容易发生哈希碰撞;即不同系统状态,但哈希值相同