1. 程式人生 > 其它 >題解 Luogu P4818

題解 Luogu P4818

P4818 [USACO15DEC]Bessie's Dream G - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

模擬題?

因為圖較大,考慮記憶化。


定義 \(dis[i][j][1/0][pre]\) 表示當前位置為 \((i,j)\),是 / 否攜帶氣味,且來到這個位置的方向為 \(pre\) 所需要的最小步數。

如果搜尋到某時刻目前狀態的 \(dis\)​ 小於等於記錄的步數,就結束當前的搜尋。


首先定義結構體:

struct node
{
	int x, y, step, smell, pre;
};

開一個結構體佇列來 BFS 就好了。


定義 \(check(x, y, smell)\)
​ 來檢查擴充套件到的點的合法性:

inline bool check(int x, int y, int smell)
{
	if(x < 1 || x > n || y < 1 || y > m)
	{
		return 0;
	}
	if(!a[x][y] || (a[x][y] == 3 && !smell))
	{
		return 0;
	}
	return 1;
}

然後實現 \(update(node\ u)\)​ 函式,對當前點狀態為 \(u\)​ 的情況進行擴充套件:

const int dx[5] = {0, 1, 0, 0, -1}, dy[5] = {0, 0, 1, -1, 0};
inline void update(node u)
{
	for(int i = 1; i <= 4; i++)
	{
		int xx = u.x + dx[i], yy = u.y + dy[i];
		if(check(xx, yy, u.smell))
		{
			if(a[xx][yy] == 2)
			{
				q.push((node){xx, yy, u.step + 1, 1, 0});
			}
			else if(a[xx][yy] == 4)
			{
				q.push((node){xx, yy, u.step + 1, 0, i});
			}
			else
			{
				q.push((node){xx, yy, u.step + 1, u.smell, 0});
			}
		}
	}
	return;
}

然後 \(bfs\)​ 函式就比較顯然了:

inline void bfs()
{
	q.push((node){1, 1, 0, 0, 0});
	while(!q.empty())
	{
		node u = q.front();
		q.pop();
		if(dis[u.x][u.y][u.smell][u.pre] <= u.step)
		{
			continue;
		}
		dis[u.x][u.y][u.smell][u.pre] = u.step;
		if(u.pre)
		{
			int xx = u.x + dx[u.pre], yy = u.y + dy[u.pre];
			if(!check(xx, yy, u.smell))
			{
				update(u);
			}
			else if(a[xx][yy] == 4)
			{
				q.push((node){xx, yy, u.step + 1, u.smell, u.pre});
			}
			else
			{
				if(a[xx][yy] == 2)
				{
					q.push((node){xx, yy, u.step + 1, 1, 0});
				}
				else
				{
					q.push((node){xx, yy, u.step + 1, u.smell, 0});
				}
			}
			continue;
		}
		update(u);
	}
	return;
}

最後在所有的 \(dis[n][m]\) 中取最小值輸出即可。


Code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 1005
struct node
{
	int x, y, step, smell, pre;
};
queue<node> q;
int n, m, a[N][N], dis[N][N][2][5];
inline bool check(int x, int y, int smell)
{
	if(x < 1 || x > n || y < 1 || y > m)
	{
		return 0;
	}
	if(!a[x][y] || (a[x][y] == 3 && !smell))
	{
		return 0;
	}
	return 1;
}
const int dx[5] = {0, 1, 0, 0, -1}, dy[5] = {0, 0, 1, -1, 0};
inline void update(node u)
{
	for(int i = 1; i <= 4; i++)
	{
		int xx = u.x + dx[i], yy = u.y + dy[i];
		if(check(xx, yy, u.smell))
		{
			if(a[xx][yy] == 2)
			{
				q.push((node){xx, yy, u.step + 1, 1, 0});
			}
			else if(a[xx][yy] == 4)
			{
				q.push((node){xx, yy, u.step + 1, 0, i});
			}
			else
			{
				q.push((node){xx, yy, u.step + 1, u.smell, 0});
			}
		}
	}
	return;
}
inline void bfs()
{
	q.push((node){1, 1, 0, 0, 0});
	while(!q.empty())
	{
		node u = q.front();
		q.pop();
		if(dis[u.x][u.y][u.smell][u.pre] <= u.step)
		{
			continue;
		}
		dis[u.x][u.y][u.smell][u.pre] = u.step;
		if(u.pre)
		{
			int xx = u.x + dx[u.pre], yy = u.y + dy[u.pre];
			if(!check(xx, yy, u.smell))
			{
				update(u);
			}
			else if(a[xx][yy] == 4)
			{
				q.push((node){xx, yy, u.step + 1, u.smell, u.pre});
			}
			else
			{
				if(a[xx][yy] == 2)
				{
					q.push((node){xx, yy, u.step + 1, 1, 0});
				}
				else
				{
					q.push((node){xx, yy, u.step + 1, u.smell, 0});
				}
			}
			continue;
		}
		update(u);
	}
	return;
}
inline void debug()
{
	putchar(10);
	putchar(10);
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= n; j++)
		{
			int tmp = 0x3f3f3f3f;
			for(int k = 0; k <= 5; k++)
			{
				tmp = min(tmp, min(dis[i][j][0][k], dis[i][j][1][k]));
			}
			printf("%d ", (tmp == 0x3f3f3f3f ? -1 : tmp));
		}
		putchar(10);
	}
	putchar(10);
	putchar(10);
	return;
}
signed main()
{
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++)
	{
		for(int j = 1; j <= m; j++)
		{
			scanf("%d", &a[i][j]);
		}
	}
	memset(dis, 0x3f, sizeof(dis));
	bfs();
	//debug();
	int ans = 0x3f3f3f3f;
	for(int i = 0; i <= 5; i++)
	{
		ans = min(ans, min(dis[n][m][0][i], dis[n][m][1][i]));
	}
	printf("%d", (ans == 0x3f3f3f3f ? -1 : ans));
	return 0;
}