[USACO17FEB]Why Did the Cow Cross the Road I G

一开始想写$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\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ivanovcraft/p/9754397.html