# P2937 [USACO09JAN] Laserphones S
P2937 [USACO09JAN] Laserphones S
题目描述
奶牛们有一个新的激光系统,这样它们在牧场上时可以进行随意的交谈。牧场被建模为一个 $W \times H$ 的点阵($1 \leq W \leq 100$,$1 \leq H \leq 100$)。
该系统需要某种视线连通性以维持通信。当然,牧场上有岩石和树木会干扰通信,但奶牛们购买了对角镜(如下的 '/' 和 '\')来使激光束偏转 90 度。下面是一个说明问题的地图。
对于这张地图,$H$ 是 8,$W$ 是 7。两个正在通信的奶牛用 'C' 表示;岩石和其他阻挡元素用 '*' 表示:
7 . . . . . . . 7 . . . . . . .
6 . . . . . . C 6 . . . . . /-C
5 . . . . . . * 5 . . . . . | *
4 * * * * * . * 4 * * * * * | *
3 . . . . * . . 3 . . . . * | .
2 . . . . * . . 2 . . . . * | .
1 . C . . * . . 1 . C . . * | .
0 . . . . . . . 0 . \-------/ .
0 1 2 3 4 5 6 0 1 2 3 4 5 6
确定必须安装的最少镜子数量 $M$,以维持两头奶牛之间的激光通信。在给定的测试数据中,这一壮举总是可能的。
输入格式
* 第 1 行:两个用空格分隔的整数:$W$ 和 $H$
* 第 2 行到第 $H+1$ 行:整个牧场。
输出格式
* 第 1 行:一个整数:$M$
输入输出样例 #1
输入 #1
7 8
.......
......C
......*
*****.*
....*..
....*..
.C..*..
.......
输出 #1
3
说明/提示
(由 ChatGPT 4o 翻译)
题解
本题的关键就在于求出最短路径的中的转向次数,题目让我们求镜子的最小值,每次转向就意味着需要一枚镜子
首先我们在定义结构体时在有方向的基础上加入turn即(转向的次数)即可
点击查看代码
typedef struct{
int x,y;
int dir;
int turn;
}Node;
点击查看代码
while (front < rear) {
Node now = queue[front++];
int dir = now.dir;
// 向当前方向继续移动
int nx = now.x + dx[dir];
int ny = now.y + dy[dir];
if (nx >= 0 && nx < h && ny >= 0 && ny < w && map[nx][ny] != '*') {
if (visited[nx][ny][dir] > now.turn) {
visited[nx][ny][dir] = now.turn;
queue[rear++] = (Node){nx, ny, dir, now.turn};
}
}
// 尝试转向
for (int d = 0; d < 4; d++) {
if (d == dir)
continue; //一致的就跳过
nx = now.x + dx[d];
ny = now.y + dy[d];
if (nx >= 0 && nx < h && ny >= 0 && ny < w && map[nx][ny] != '*') {
if (visited[nx][ny][d] > now.turn + 1) {
visited[nx][ny][d] = now.turn + 1;
queue[rear++] = (Node){nx, ny, d, now.turn + 1};
}
}
}
}
点击查看代码
// 向当前方向继续移动
int nx = now.x + dx[dir];
int ny = now.y + dy[dir];
点击查看代码
// 尝试转向
for (int d = 0; d < 4; d++) {
if (d == dir)
continue;
nx = now.x + dx[d];
ny = now.y + dy[d];
点击查看代码
int cx[2], cy[2], count = 0;
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
if (map[i][j] == 'C'){
cx[count] = i;
cy[count] = j;
count++;
}
int ans = BFS(cx[0], cy[0], cx[1], cy[1]);
完整代码如下
点击查看代码
#include <stdio.h>
#define MAXN 105
typedef struct{
int x,y;
int dir;
int turn;
}Node;
int w,h;
char map[MAXN][MAXN];
int visited[MAXN][MAXN][4];
int dx[] = {1,-1,0,0}; //通信的方向是上下左右
int dy[] = {0,0,1,-1};
int BFS(int sx, int sy, int ex, int ey){
Node queue [MAXN * MAXN * 4];
int front = 0, rear = 0;
// 初始化 visited 数组
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
for (int d = 0; d < 4; d++)
visited[i][j][d] = 1e9;
// 从起点向四个方向尝试出发
for (int d = 0; d < 4; d++) {
visited[sx][sy][d] = 0;
queue[rear++] = (Node){sx, sy, d, 0};
}
while (front < rear) {
Node now = queue[front++];
int dir = now.dir;
// 向当前方向继续移动
int nx = now.x + dx[dir];
int ny = now.y + dy[dir];
if (nx >= 0 && nx < h && ny >= 0 && ny < w && map[nx][ny] != '*') {
if (visited[nx][ny][dir] > now.turn) {
visited[nx][ny][dir] = now.turn;
queue[rear++] = (Node){nx, ny, dir, now.turn};
}
}
// 尝试转向
for (int d = 0; d < 4; d++) {
if (d == dir)
continue;
nx = now.x + dx[d];
ny = now.y + dy[d];
if (nx >= 0 && nx < h && ny >= 0 && ny < w && map[nx][ny] != '*') {
if (visited[nx][ny][d] > now.turn + 1) {
visited[nx][ny][d] = now.turn + 1;
queue[rear++] = (Node){nx, ny, d, now.turn + 1};
}
}
}
}
// 取四个方向的最小值
int result = 1e9;
for (int d = 0; d < 4; d++) {
if (visited[ex][ey][d] < result)
result = visited[ex][ey][d];
}
return result;
}
int main(){
scanf("%d%d",&w, &h);
for (int i = 0; i < h; i++) {
scanf("%s", map[i]);
}
//因为是两只C奶牛之间的通信,用数组记录两只先后出现的奶牛
int cx[2], cy[2], count = 0;
for (int i = 0; i < h; i++)
for (int j = 0; j < w; j++)
if (map[i][j] == 'C'){
cx[count] = i;
cy[count] = j;
count++;
}
int ans = BFS(cx[0], cy[0], cx[1], cy[1]);
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号