USACO 2.4.1 The Tamworth Two
牛和农夫按照固定的走法在10x10的地图中走,每分钟走一步,求经过几分钟相遇。永远不能相遇输出0。
纯模拟的题。
判断永远不能相遇的方法是如果遇到了一个先前的状态,那么肯定存在循环,必定不能相遇。
程序中把状态表示为牛和农夫的位置以及面向的方向,通过map判断是否遇到重复状态,因为map中不存在的键会有默认值,对于bool来说就是false。
一点点空间的优化是地图只用存一份,牛和农夫不显示在地图上,尽通过状态里的点间接表示。
/*
ID: xjtuacm1
PROG: ttwo
LANG: C++
*/
#include<iostream>
#include<stack>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
const int N = 10;
enum direction {NORTH, EAST, SOUTH, WEST};
struct point
{
int x, y;
point(int xx= 0, int yy = 0) :x(xx), y(yy) {}
void set(int xx, int yy)
{
x = xx;
y = yy;
}
bool operator==(const point& pt) const
{
return x == pt.x && y == pt.y;
}
};
struct state
{
int d[2];
point pt[2];
state() { d[0] = d[1] = NORTH; }
bool operator<(const state& s) const
{
return memcmp(this, &s, sizeof(state)) < 0;
}
};
map<state, bool> h;
char pane[N][N];
inline bool inRange(point pt)
{
return pt.x >= 0
&& pt.x < 10
&& pt.y >= 0
&& pt.y < 10;
}
bool met(const state& s)
{
return s.pt[0] == s.pt[1];
}
void next(state& s)
{
point npt[2];
for(int i = 0; i!= 2; i++)
{
switch(s.d[i])
{
case NORTH:
npt[i].set(s.pt[i].x - 1, s.pt[i].y);
break;
case EAST:
npt[i].set(s.pt[i].x, s.pt[i].y + 1);
break;
case SOUTH:
npt[i].set(s.pt[i].x + 1, s.pt[i].y);
break;
case WEST:
npt[i].set(s.pt[i].x, s.pt[i].y - 1);
break;
}
if(inRange(npt[i])
&& pane[npt[i].x][npt[i].y] != '*')
{
s.pt[i] = npt[i];
}
else
{
s.d[i] += 1;
s.d[i] %= 4;
}
}
}
int main(int argc, char *argv[])
{
freopen("ttwo.in", "r", stdin);
#ifndef USACO
freopen("ttwo.out", "w", stdout);
#endif // USACO
state s;
for(int i = 0; i!= N; i++)
for(int j = 0; j!= N; j++)
{
scanf("%c", &pane[i][j]);
if(pane[i][j] == '\n')
scanf("%c", &pane[i][j]);
if(pane[i][j] == 'F'
|| pane[i][j] == 'C')
{
int t = (pane[i][j] - 'C' == 0 ? 0 : 1);
s.pt[t].set(i, j);
pane[i][j] = '.';
}
}
int minute = 0;
h[s] = true;
while(!met(s))
{
next(s);
if(h[s])
{
printf("0\n");
return 0;
}
h[s] = true;
minute++;
}
printf("%d\n", minute);
return 0;
}
BTW,纯模拟真心考验细心程度= =。。。。