pjT3翻车了,怕是连pj组都不如
这道题一看上去就是用bfs的啊,用dfs还怕爆栈。
然后就手动地打了个非常暴力的bfs,只拿到了25pts。
翻了题解才知道这个东西居然还能用spfa!
总结性话语:搜索题不会做的,试着转换成图论题,用图论题的思路解决暴力模拟也许会更方便。
所以我们可以类似于spfa,建立一个vis数组和dist数组。
如何记录状态?
当前行列肯定要记的,然后就要考虑那个花两块钱变色的东西。
不难发现再开一维记录当前位置的颜色即可,不需要去更改原矩阵。当原颜色与当前颜色不一样的时候就说明我使用了膜法。
有一个贪心的做法:当我下一步是一个无颜色的格子,那么最优的是直接指定为同样颜色,这样只要花两块钱,不然要花三块钱。
对于不同的颜色,注意去分别判断,用类似于spfa的方法去更新。
所以就完事了。最后输出一下std::min(dist[n][n][0], dist[n][n][1])
就可以了。
代码:
#include<cstdio>
#include<cstring>
#include<queue>
const int maxn = 105;
const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};
struct Nodes
{
int x, y, col;
Nodes(int x, int y, int col):x(x), y(y), col(col){}
};
int G[maxn][maxn];
int dist[maxn][maxn][2];
bool vis[maxn][maxn][2];
int n, m;
int main()
{
memset(dist, 0x3f, sizeof dist);
memset(G, -1, sizeof G);
scanf("%d%d", &n, &m);
while(m--)
{
int x, y, z; scanf("%d%d%d", &x, &y, &z);
G[x][y] = z;
}
std::queue<Nodes> q;
dist[1][1][G[1][1]] = 0;
q.push(Nodes(1, 1, G[1][1])); vis[1][1][G[1][1]] = true;
while(!q.empty())
{
Nodes u = q.front(); q.pop();
int x = u.x, y = u.y, col = u.col, res = dist[x][y][col];
vis[x][y][col] = false;
for(int i = 0; i < 4; i++)
{
int nx = x + dx[i], ny = y + dy[i];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= n)
{
if(G[nx][ny] == -1)
{
if(G[x][y] == -1) continue;
if(res + 2 < dist[nx][ny][col])
{
dist[nx][ny][col] = res + 2;
if(!vis[nx][ny][col])
{
q.push(Nodes(nx, ny, col));
vis[nx][ny][col] = true;
}
}
}
else if(G[nx][ny] != col)
{
if(res + 1 < dist[nx][ny][G[nx][ny]])
{
dist[nx][ny][G[nx][ny]] = res + 1;
if(!vis[nx][ny][G[nx][ny]])
{
q.push(Nodes(nx, ny, G[nx][ny]));
vis[nx][ny][G[nx][ny]] = true;
}
}
}
else if(G[nx][ny] == col)
{
if(res < dist[nx][ny][G[nx][ny]])
{
dist[nx][ny][G[nx][ny]] = res;
if(!vis[nx][ny][G[nx][ny]])
{
q.push(Nodes(nx, ny, G[nx][ny]));
vis[nx][ny][G[nx][ny]] = true;
}
}
}
}
}
}
int ans;
if(G[n][n] != -1) ans = dist[n][n][G[n][n]];
else ans = std::min(dist[n][n][0], dist[n][n][1]);
if(ans != 0x3f3f3f3f) printf("%d\n", ans);
else printf("-1\n");
return 0;
}