题解:洛谷 P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two

【题目来源】

洛谷:[P1518 USACO2.4] 两只塔姆沃斯牛 The Tamworth Two - 洛谷 (luogu.com.cn)

【题目描述】

两只牛逃跑到了森林里。Farmer John 开始用他的专家技术追捕这两头牛。你的任务是模拟他们的行为(牛和 John)。

追击在 \(10\times 10\) 的平面网格内进行。一个格子可以是:一个障碍物,两头牛(它们总在一起),或者 Farmer John。两头牛和 Farmer John 可以在同一个格子内(当他们相遇时),但是他们都不能进入有障碍的格子。

一个格子可以是:

  • . 空地;
  • * 障碍物;
  • C 两头牛;
  • F Farmer John。

这里有一个地图的例子:

*...*.....
......*...
...*...*..
..........
...*.F....
*.....*...
...*......
..C......*
...*.*....
.*.*......

牛在地图里以固定的方式游荡。每分钟,它们可以向前移动或是转弯。如果前方无障碍(地图边沿也是障碍),它们会按照原来的方向前进一步。否则它们会用这一分钟顺时针转 \(90\) 度。 同时,它们不会离开地图。

Farmer John 深知牛的移动方法,他也这么移动。

每次(每分钟)Farmer John 和两头牛的移动是同时的。如果他们在移动的时候穿过对方,但是没有在同一格相遇,我们不认为他们相遇了。当他们在某分钟末在某格子相遇,那么追捕结束。

读入十行表示地图。每行都只包含 \(10\) 个字符,表示的含义和上面所说的相同。保证地图中只有一个 F 和一个 CFC 一开始不会处于同一个格子中。

计算 Farmer John 需要多少分钟来抓住他的牛,假设牛和 Farmer John 一开始的行动方向都是正北(即上)。 如果 John 和牛永远不会相遇,输出 \(0\)

【输入】

输入共十行,每行 \(10\) 个字符,表示如上文描述的地图。

【输出】

输出一个数字,表示 John 需要多少时间才能抓住牛们。如果 John 无法抓住牛,则输出 \(0\)

【输入样例】

*...*.....
......*...
...*...*..
..........
...*.F....
*.....*...
...*......
..C......*
...*.*....
.*.*......

【输出样例】

49

【算法标签】

《洛谷 P1518 两只塔姆沃斯牛》 #模拟# #USACO#

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int m[15][15] = {0};  // 地图数组,0 表示障碍,1 表示可通行
int dx[4] = {-1, 0, 1, 0};  // 方向数组:北、东、南、西 的 x 偏移量
int dy[4] = {0, 1, 0, -1};  // 方向数组:北、东、南、西 的 y 偏移量

// 定义 farmer 和 cow 的结构体
struct shiti 
{
    int x;  // 当前行坐标
    int y;  // 当前列坐标
    int f;  // 当前方向:0 北,1 东,2 南,3 西
} cow, farmer;  // cow 表示牛,farmer 表示农夫

// 移动函数:模拟农夫和牛的移动
void move() 
{
    // 计算农夫和牛的前方位置
    int fx = farmer.x + dx[farmer.f], fy = farmer.y + dy[farmer.f];  // 农夫的前方位置
    int cx = cow.x + dx[cow.f], cy = cow.y + dy[cow.f];  // 牛的前方位置

    // 农夫移动逻辑
    if (m[fx][fy]) 
	{  // 如果农夫前方可通行
        farmer.x = fx;  // 更新农夫的位置
        farmer.y = fy;
    } 
	else 
	{  // 如果前方是障碍
        farmer.f = (farmer.f + 1) % 4;  // 农夫转向(顺时针旋转 90 度)
    }

    // 牛移动逻辑
    if (m[cx][cy]) 
	{  // 如果牛前方可通行
        cow.x = cx;  // 更新牛的位置
        cow.y = cy;
    } 
	else 
	{  // 如果前方是障碍
        cow.f = (cow.f + 1) % 4;  // 牛转向(顺时针旋转 90 度)
    }
}

int main() {
    int timek = 0;  // 记录时间(移动次数)
    char tmpc;  // 用于临时读取地图字符
    bool mark[11][11][4][11][11][4] = {0};  // 状态标记数组,用于记录农夫和牛的位置和方向是否重复

    // 构建地图
    for (int i = 1; i <= 10; i++) 
	{
        for (int j = 1; j <= 10; j++) 
		{
            cin >> tmpc;  // 读取地图字符
            if (tmpc == '*') continue;  // 如果是障碍物,跳过
            m[i][j] = 1;  // 标记为可通行
            if (tmpc == 'C') 
			{  // 如果是牛
                cow.x = i;  // 记录牛的初始位置
                cow.y = j;
                cow.f = 0;  // 初始方向为北
            }
            if (tmpc == 'F') 
			{  // 如果是农夫
                farmer.x = i;  // 记录农夫的初始位置
                farmer.y = j;
                farmer.f = 0;  // 初始方向为北
            }
        }
    }

    // 模拟运动
    while (farmer.x != cow.x || farmer.y != cow.y) 
	{  // 当农夫和牛不在同一位置时循环
        timek++;  // 时间增加
        if (mark[farmer.x][farmer.y][farmer.f][cow.x][cow.y][cow.f] == 1) 
		{  // 如果当前状态已出现过
            cout << 0;  // 输出 0(表示无法相遇)
            return 0;
        }
        mark[farmer.x][farmer.y][farmer.f][cow.x][cow.y][cow.f] = 1;  // 标记当前状态
        move();  // 农夫和牛移动
    }

    // 输出相遇时间
    cout << timek;
    return 0;
}

【运行结果】

*...*.....
......*...
...*...*..
..........
...*.F....
*.....*...
...*......
..C......*
...*.*....
.*.*......
49
posted @ 2026-02-17 08:23  团爸讲算法  阅读(2)  评论(0)    收藏  举报