/*
这题本身不难, 但是我写难了
就是一个bfs, 没了
但是我的写法恰好犯了一个错误
hark数据
3 5
1 1 0
2 1 1
3 1 1
2 2 0
3 3 0
答案是4而我能输出3
0 -1 -1
1 0 -1
1 -1 0
原因是 我先走到了(2, 2)这时候到(3, 2)的花费最小是4, 我还加入了队列, 这时候的上一个颜色是0, 这个记为a
然后, 我后面又走到了(3, 1)从这个到(3, 2) 更新了最小花费为3, 我也加入了队列, 这时候的上一个颜色是1, 这个记为b
但是前面花费是4的时候我加入了队列(a), 上一个颜色是0, 导致走到(3, 3)时上个颜色是0 和 (3, 3)的0相等不花费
就把到(3, 3)的最小花费变成了3, 就错了,
使用优先队列, 用到每个点的最小距离排, 就可以解决这个问题, 就可以先算b, 把正确答案算出来
这里说一下优先队列的结构体排序
众所周知优先队列默认是大根堆
是从大到小排, 但是是用的小于号, 这时候直接重载小于号像下面就行了, 不用更换模式
*/
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1100, M = 110;
int g[M][M];
int n, m;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// bool st[M][M];
int dist[M][M];
struct Node
{
int sum;
int x, y;
bool flag; // 到这一步是否使用了魔法
int now; // now是当前的颜色, 因为不能更改嘛, 用这个记录一下这次的颜色
bool operator< (const Node &W)const
{
return sum < W.sum;
}
};
int bfs()
{
memset(dist, 0x3f, sizeof dist);
priority_queue<Node> q;
q.push({0, 1, 1, 0, g[1][1]});
dist[1][1] = 0;
while (q.size())
{
auto t = q.top();
q.pop();
int x = t.x, y = t.y, now = t.now;
bool flag = t.flag;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i], s = 0; // s是这次走的花费
if (a < 1 || b < 1 || a > n || b > n) continue;
if (g[a][b] != now) // 如果颜色不同
{
if (g[a][b] >= 0) s = 1; // 这个点有颜色
else if (!flag) s = 2; // 没颜色且之前没用过魔法
else continue; // 说明已经到不了了
}
if (dist[a][b] > dist[x][y] + s)
{
dist[a][b] = dist[x][y] + s;
// if (a == 4 && b == 4) cout << x << ' ' << y << ' ' << now << endl;
// cout << a << ' ' << b << endl;
q.push({dist[a][b], a, b, s == 2, s == 2 ? now : g[a][b]}); // 这段话可以细品 s == 2 ? now : g[a][b]是如果使用了魔法, 那么这个点的颜色就是上个点的颜色, 没有的话就是它自身的颜色
}
}
}
return dist[n][n];
}
int main()
{
memset(g, -1, sizeof g);
cin >> n >> m;
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = c + 6;
}
// for (int i = 1; i <= n; i ++ )
// {
// for (int j = 1; j <= n; j ++ )
// printf("%2d ", g[i][j]);
// puts("");
// }
int t = bfs();
if (t != 0x3f3f3f3f) cout << t;
else cout << -1;
return 0;
}
// 错误的写法
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int N = 1100, M = 110;
int g[M][M];
int n, m;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// bool st[M][M];
int dist[M][M];
struct Node
{
int x, y;
bool flag;
int now;
};
int bfs()
{
memset(dist, 0x3f, sizeof dist);
queue<Node> q;
q.push({1, 1, 0, g[1][1]});
dist[1][1] = 0;
while (q.size())
{
auto t = q.front();
q.pop();
int x = t.x, y = t.y, now = t.now;
bool flag = t.flag;
for (int i = 0; i < 4; i ++ )
{
int a = x + dx[i], b = y + dy[i], s = 0;
if (a < 1 || b < 1 || a > n || b > n) continue;
if (g[a][b] != now)
{
if (g[a][b] >= 0) s = 1;
else if (!flag) s = 2;
else continue; // 说明已经到不了了
}
if (dist[a][b] > dist[x][y] + s)
{
dist[a][b] = dist[x][y] + s;
if (a == 4 && b == 4) printf("%d %d %d %d %d %d\n", x, y, s, g[a][b], g[x][y], now);
// cout << a << ' ' << b << endl;
q.push({a, b, s == 2, (s == 2) ? now : g[a][b]});
}
}
}
return dist[n][n];
}
int main()
{
memset(g, -1, sizeof g);
cin >> n >> m;
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
g[a][b] = c;
}
for (int i = 1; i <= n; i ++ )
{
for (int j = 1; j <= n; j ++ )
printf("%2d ", g[i][j]);
puts("");
}
int t = bfs();
if (t != 0x3f3f3f3f) cout << t;
else cout << -1;
return 0;
}
标签:NOIP2017,棋盘,dist,int,include,flag,bool,now,P3956
From: https://www.cnblogs.com/blind5883/p/18134200