版权声明:若转载请附上原博客链接,谢谢! https://blog.csdn.net/Link_Ray/article/details/83338765
题意
给定一个 的网格,每个网格都由 中的数字填充,一开始从1号格开始走,有三种走法。
- 走日字格
- 横走或竖走(走的格子不限)
- 沿着对角线走(走的格子不限)
每个格子可以重复行走。
每走到一个格子行走次数+1,同时当每次切换不同的行走方式时,行走次数也要+1,问从1号到2号再到3号…一直到
号格子的最少行走次数是多少,当行走次数相同,那最少的切换次数是多少。
题解
因为我们需要知道从某个点到另一个点之间的最短路径,所以需先计算一下最短路。
先定义一个
,
代表行走次数,
代表切换次数用来代表边权。
每个格子可以分成三个点,
代表行走的方式,这里可以将点的状态进行压缩一下变成
,然后将所有的点都连接起来,因为切换方式只会在自己格子中切换(不能边走边换)所以
不相同的点,只需与自己的格子中的点连边,边权为
,然后所有格子中
相同的点再连边,边权为
。
然后跑一遍floyd算出每两点之间的最短路径,因为每个点都有三种状态,我们不知道哪种开始走是最优的,所以需要dp递推一下。所以就从 号点开始dp直到 号点。
代码
```#include <bits/stdc++.h>
using namespace std;
#define x first
#define y second
const int maxn = 305;
const int M = 305;
const int inf = 0x3f3f3f3f;
const int dr[] = {-2, -1, 1, 2, 2, 1, -1, -2};
const int dc[] = { 1, 2, 2, 1, -1, -2, -2, -1};
typedef pair<int,int> pii;
int n;
int a[maxn][maxn];
pii pos[maxn];
pii dis[maxn][maxn];
pii dp[maxn][3];
bool in(int x,int y) {
if(x < 0 || x >= n || y < 0 || y >= n)
return false;
return true;
}
int get(int x,int y, int p) {
return x*3*n+y*3+p;
}
pii operator + (const pii& p1, const pii& p2) {
return pii(p1.x+p2.x,p1.y+p2.y);
}
int main() {
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
scanf("%d", &a[i][j]);
--a[i][j];
pos[a[i][j]] = pii(i,j);
}
}
for(int i = 0; i < M; ++i)
for(int j = 0; j < M; ++j)
dis[i][j] = pii(inf,inf);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
// knight
for(int k = 0; k < 8; ++k) {
int ni = i+dr[k], nj = j+dc[k];
if(!in(ni,nj)) continue;
dis[get(i,j,2)][get(ni,nj,2)] = pii(1,0);
}
// rook
for(int k = 0; k < n; ++k) {
if(k != j)
dis[get(i,j,1)][get(i,k,1)] = pii(1,0);
if(k != i)
dis[get(i,j,1)][get(k,j,1)] = pii(1,0);
}
// bugt
for(int k = 1; k < n; ++k) {
int ni = i+k, nj = j+k;
if(in(ni,nj)) dis[get(i,j,0)][get(ni,nj,0)] = pii(1,0);
ni = i-k, nj = j-k;
if(in(ni,nj)) dis[get(i,j,0)][get(ni,nj,0)] = pii(1,0);
ni = i+k, nj = j-k;
if(in(ni,nj)) dis[get(i,j,0)][get(ni,nj,0)] = pii(1,0);
ni = i-k, nj = j+k;
if(in(ni,nj)) dis[get(i,j,0)][get(ni,nj,0)] = pii(1,0);
}
//
for(int k = 0; k < 3; ++k)
for(int l = 0; l < 3; ++l) {
if(l != k)
dis[get(i,j,k)][get(i,j,l)] = pii(1,1);
}
}
}
for(int k = 0; k < M; ++k)
for(int i = 0; i < M; ++i)
for(int j = 0; j < M; ++j) {
dis[i][j] = min(dis[i][j], dis[i][k]+dis[k][j]);
}
/*
for(int i = 0; i < M; ++i)
for(int j = 0; j < M; ++j)
printf("%d %d %d\n", i, j, dis[i][j].x);
*/
for(int i = 0; i < n*n; ++i)
for(int k = 0; k < 3; ++k)
dp[i][k] = pii(inf,inf);
for(int k = 0; k < 3; ++k)
dp[0][k] = pii(0,0);
for(int i = 0; i < n*n-1; ++i) {
for(int k = 0; k < 3; ++k) {
for(int l = 0; l < 3; ++l) {
dp[i+1][k] = min(dp[i+1][k], dp[i][l]+dis[get(pos[i].x,pos[i].y,l)][get(pos[i+1].x,pos[i+1].y,k)]);
}
}
}
pii ans(inf,inf);
ans = min(ans, dp[n*n-1][0]);
ans = min(ans, dp[n*n-1][1]);
ans = min(ans, dp[n*n-1][2]);
printf("%d %d\n", ans.x, ans.y);
return 0;
}