一开始想写$DP$,发现直接转移完全有后效性
所以本小蒟蒻写了个最短路
每走三步就要吃草是这个题最难搞的地方,我们建图时不妨只对于距离等于三的点连边
考虑完全覆盖所有情况,从一个点走一步,两步,然后三步,和直接走三步代价是等价的
这样从每个点到与其曼哈顿距离为三的所有点连边即可
考虑到终点的答案,对于所有小于三步到终点的位置到终点的代价,找到最小值即为答案
有个坑就是比如右左右这种走法,我们也需要从一个点向其周围的点连边
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define int long long using namespace std; const int maxn=20010; struct edge{ int next,to,dis; }e[12*maxn]; int n,t,g[110][110],len[maxn],head[maxn],cnt,ans=1e9; int dx[]={-1,-2,-3,-1,-2,0,1,2,1,2,3,0,0,1,0,-1}; int dy[]={-2,-1,0,2,1,-3,-2,-1,2,1,0,3,1,0,-1,0}; bool exist[maxn]; inline void add(int x,int y,int d) { e[++cnt].next=head[x]; e[cnt].to=y; e[cnt].dis=d; head[x]=cnt; } inline int make(int x,int y) { return x*n+y; } int dijkstra() { priority_queue<pair<int,int> >q; memset(len,0x3f,sizeof(len)); q.push(make_pair(0,make(1,1))); len[make(1,1)]=0; while(!q.empty()) { int u=q.top().second; q.pop(); if(exist[u]) continue; exist[u]=1; for(int v,i=head[u];i;i=e[i].next) if(len[v=e[i].to]>len[u]+e[i].dis) { len[v]=len[u]+e[i].dis; q.push(make_pair(-len[v],v)); } } } void check(int x,int y) { for(int i=0;i<16;i++) if(x+dx[i]>0&&x+dx[i]<=n&&y+dy[i]>0&&y+dy[i]<=n) add(make(x,y),make(x+dx[i],y+dy[i]),3*t+g[x+dx[i]][y+dy[i]]); } signed main() { scanf("%lld%lld",&n,&t); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%lld",&g[i][j]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) check(i,j); dijkstra(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(2*n-i-j<3) ans=min(ans,len[make(i,j)]+(2*n-i-j)*t); printf("%lld ",ans); return 0; }