链接
对每一个点(x, y)编号
int make(int x, int y){
return (x - 1) * n + y;
}
由于奶牛走3步才休息,而三步中包含走两步和一步的情况,所以我们直接枚举三步,省去加一条和两条边的情况。
const int dx[]={
-2,-1,1,2,2,1,-1,-2,0,1,0,-1,0,3,0,-3};
const int dy[]={
1,2,2,1,-1,-2,-2,-1,1,0,-1,0,3,0,-3,0};
加边
void connect(int x, int y){
for (int i = 0; i < 16; ++i) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 1 && ny >= 1 && nx <= n && ny <= n){
add(make(x, y), make(nx, ny), a[nx][ny] + 3 * t);
}
}
}
但是并没有枚举完全,比如说题目给的样例
4 2
30 92 36 10
38 85 60 16
41 13 5 68
20 97 13 80
由5到80只走了两步。
考虑加上特殊边,即走两步或1步可以到达终点。于是补充这些边。
add(make(n - 1, n), make(n, n), t);
add(make(n, n - 1), make(n, n), t);
add(make(n - 2, n), make(n, n), t << 1);
add(make(n, n- 2), make(n, n), t << 1);
add(make(n - 1, n - 1), make(n, n), t << 1);
code
#include <cstdio>
#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 105;
const int M = N * N << 4;
int n, t, cnt;
int a[N][N], vis[N * N], head[M];
long long dis[N * N];
const int dx[]={
-2,-1,1,2,2,1,-1,-2,0,1,0,-1,0,3,0,-3};
const int dy[]={
1,2,2,1,-1,-2,-2,-1,1,0,-1,0,3,0,-3,0};
struct edge{
int to, nxt, val;
}e[M];
inline void add(int u, int v, int w){
e[++cnt] = {
v, head[u], w};
head[u] = cnt;
}
int make(int x, int y){
return (x - 1) * n + y;
}
void connect(int x, int y){
for (int i = 0; i < 16; ++i) {
int nx = x + dx[i];
int ny = y + dy[i];
if (nx >= 1 && ny >= 1 && nx <= n && ny <= n){
add(make(x, y), make(nx, ny), a[nx][ny] + 3 * t);
}
}
}
void SPFA(){
queue<int> que;
memset(vis, 0, sizeof vis);
memset(dis, 0x3f, sizeof dis);
dis[make(1, 1)] = 0;
que.push(make(1, 1));
while (!que.empty()){
int u = que.front();
que.pop();
vis[u] = 0;
for (int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if (dis[v] > dis[u] + e[i].val){
dis[v] = dis[u] + e[i].val;
if (!vis[v]) vis[v] = 1, que.push(v);
}
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie();
cin >> n >> t;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
cin >> a[i][j];
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
connect(i, j);
}
}
add(make(n - 1, n), make(n, n), t);
add(make(n, n - 1), make(n, n), t);
add(make(n - 2, n), make(n, n), t << 1);
add(make(n, n- 2), make(n, n), t << 1);
add(make(n - 1, n - 1), make(n, n), t << 1);
SPFA();
cout << dis[make(n, n)] << endl;
return 0;
}