Cow Navigation(USACO)

Posted ghostfly233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cow Navigation(USACO)相关的知识,希望对你有一定的参考价值。

题目大意:

给定一个N*N的矩阵,并告诉你每一个格子能否经过,要求你求出(n,1)到(1,n)的最短路径的操作数。

其中操作有2种,第一种是沿着目前的方向走一格,第二种是向左或向右转90°

由于题目设置,一开始我们并不知道起点的方向,所以也可以理解为要我们求出朝向不同但位置相同的2个点的最短路径的方案数,但是注意,此时2个点的操作必须同时进行,比如要前进必须同时前进。

如果某一个点走到了边界外或者走到了不能经过的格子,那么他会返回并且不进行任何操作

如果一个点走到了终点那么接下来的指令它都不会执行

————————————————我是分割线————————————————

这道题目,很显然就是求最短路,然后我们自然会想到spfa

但是这个题目坑就坑在dis数组,由于我们有2个点,而且每个点都有方向,所以是6维的

dis[x1][y1][x2][y2][d1][d2]表示两个点分别从起点走到(x1,y1)方向为d1;走到(x2,y2)方向为d2

然后我们只要初始化后直接SPFA即可

记得check一下有没有超边界。

至于注意事项吗,就是别打挂了。。。暴力调了半小时。。。。。

#include<cstdio>
#include<queue>
#define min(a,b) ((a)<(b)?(a):(b))
#define inf 0x3f3f3f3f
#define MN 21
using namespace std;
int m[MN][MN],dis[MN][MN][MN][MN][5][5];
int h[]={0,-1,0,1,0},l[]={0,0,1,0,-1};
int nowx1,nowx2,nowy1,nowy2,sum1,sum2,td1,td2,ans,n;
bool c[MN][MN][MN][MN][5][5];
char ch;
struct gather{
    int x1,y1,x2,y2,d1,d2;
    gather(int x1,int y1,int x2,int y2,int d1,int d2):
        x1(x1),y1(y1),x2(x2),y2(y2),d1(d1),d2(d2){}
    gather () {}
};
queue<gather>q;
bool check(int x,int y){
    if((x<1)||(x>n)||(y<1)||(y>n))return false;
    return true;
}
void spfa()
{
    q.push(gather(n,1,n,1,1,2));
    c[n][1][n][1][1][2]=true;
    while(!q.empty()){
        gather p=q.front();
        q.pop();
        nowx1=p.x1+h[p.d1];nowx2=p.x2+h[p.d2];
        nowy1=p.y1+l[p.d1];nowy2=p.y2+l[p.d2];
        if((!check(nowx1,nowy1))||(!m[nowx1][nowy1]))nowx1=p.x1,nowy1=p.y1;
        if((!check(nowx2,nowy2))||(!m[nowx2][nowy2]))nowx2=p.x2,nowy2=p.y2;
        if(p.x1==1&&p.y1==n)nowx1=1,nowy1=n;
        if(p.x2==1&&p.y2==n)nowx2=1,nowy2=n;
        sum1=dis[nowx1][nowy1][nowx2][nowy2][p.d1][p.d2];
        sum2=dis[p.x1][p.y1][p.x2][p.y2][p.d1][p.d2];
        if(sum1>sum2+1)
        {
            dis[nowx1][nowy1][nowx2][nowy2][p.d1][p.d2]=sum2+1;
            if(!c[nowx1][nowy1][nowx2][nowy2][p.d1][p.d2])
            q.push(gather(nowx1,nowy1,nowx2,nowy2,p.d1,p.d2));
            c[nowx1][nowy1][nowx2][nowy2][p.d1][p.d2]=1;
        }
        td1=(p.d1==1)?4:p.d1-1;td2=(p.d2-1==0)?4:p.d2-1;
        sum1=dis[p.x1][p.y1][p.x2][p.y2][td1][td2];
        if(sum1>sum2+1)
        {
            dis[p.x1][p.y1][p.x2][p.y2][td1][td2]=sum2+1;
            if(!c[p.x1][p.y1][p.x2][p.y2][td1][td2])
            q.push(gather(p.x1,p.y1,p.x2,p.y2,td1,td2));
            c[p.x1][p.y1][p.x2][p.y2][td1][td2]=1;
        }
        td1=p.d1==4?1:p.d1+1;td2=p.d2==4?1:p.d2+1;
        sum1=dis[p.x1][p.y1][p.x2][p.y2][td1][td2];
        if(sum1>sum2+1)
        {
            dis[p.x1][p.y1][p.x2][p.y2][td1][td2]=sum2+1;
            if(!c[p.x1][p.y1][p.x2][p.y2][td1][td2])
            q.push(gather(p.x1,p.y1,p.x2,p.y2,td1,td2));
            c[p.x1][p.y1][p.x2][p.y2][td1][td2]=1;
        }
        c[p.x1][p.y1][p.x2][p.y2][p.d1][p.d2]=false;
    }
}

int main(){
    freopen("GP3.in","r",stdin);    
    freopen("GP3.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%c",&ch);
        for(int j=1;j<=n;j++)
        {
            scanf("%c",&ch);
            if(ch==E)m[i][j]=true;
        }
    }    
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                for(int l=1;l<=n;l++)
                    for(int dd1=1;dd1<=4;dd1++)
                        for(int dd2=1;dd2<=4;dd2++)
                        dis[i][j][k][l][dd1][dd2]=inf;
    dis[n][1][n][1][1][2]=0;
    ans=inf;
    spfa();
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
            ans=min(ans,dis[1][n][1][n][i][j]);        
    printf("%d\n",ans);                        
    fclose(stdin);
    fclose(stdout);
}

 

以上是关于Cow Navigation(USACO)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3893[Usaco2014 Dec]Cow Jog*

P2863 [USACO06JAN]牛的舞会The Cow Prom

[USACO19FEB]Cow Dating——找规律

bzoj3298[USACO 2011Open]cow checkers

[USACO08JAN]牛大赛Cow Contest

[USACO07OPEN]Catch That Cow