• 4761: [Usaco2017 Jan]Cow Navigation题解


     题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4761

    这道题我看了半天别人的题解,为了很久以后我还能看懂,所以写题解来记录一下。

    此题为usaco20171月月赛金组

    这道题是一道动归加上spfa,用dis[x1][y1][x2][y2][d1][d2]来表示两条路分别在x1,y1,面向d1,和在x2,y2,面向d2,从起点出发要到这个状态所需的最短指令。

    spfa中,分三种情况来讨论三种做法,最后的得到结果。

    具体的解释和意思在代码注释里。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    using namespace std;
    int n,m[100][100],dis[30][30][30][30][5][5]; 
    bool c[30][30][30][30][5][5];
    int nowx1,nowx2,nowy1,nowy2;
    int h[]={0,-1,0,1,0},l[]={0,0,1,0,-1};
    int sum1,ans,sum2,td1,td2;
    char a[100][100];
    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;
        else 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();//删队首集合
           //1.第一种方案,按当前方向继续向前走
          nowx1=p.x1+h[p.d1]; nowy1=p.y1+l[p.d1];
          nowx2=p.x2+h[p.d2]; nowy2=p.y2+l[p.d2];
           //以上是两条路在继续按当前方向走后,会到达的点
          if ((check(nowx1,nowy1)==false)||(m[nowx1][nowy1]==false)){
            nowx1=p.x1; nowy1=p.y1;
        }
        if ((check(nowx2,nowy2)==false)||(m[nowx2][nowy2]==false)){
            nowx2=p.x2; nowy2=p.y2;
        } 
           //以上两个if语句表示如果继续向前走一步,到达的点如果超出图的范围,或者是那个店存在石头,都是不能走的,应停留在原来的位置。
        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]==false)
            q.push(gather(nowx1,nowy1,nowx2,nowy2,p.d1,p.d2));
              //如果不在队列内,就放进去
            c[nowx1][nowy1][nowx2][nowy2][p.d1][p.d2]=true;
        }
        //2.向右转90度
        td1=p.d1+1; td2=p.d2+1; 
        if (td1>4) td1=1; if (td2>4) td2=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]==false)
            q.push(gather(p.x1,p.y1,p.x2,p.y2,td1,td2));
            c[p.x1][p.y1][p.x2][p.y2][td1][td2]=true;
        }
        //3.向左转90度
        td1=p.d1-1; td2=p.d2-1; 
        if (td1<1) td1=4; if (td2<1) td2=4;
        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]==false)
            q.push(gather(p.x1,p.y1,p.x2,p.y2,td1,td2));
            c[p.x1][p.y1][p.x2][p.y2][td1][td2]=true;
        }
        c[p.x1][p.y1][p.x2][p.y2][p.d1][p.d2]=false;
           //出队列
      }
    }
    int main()
    {
      scanf("%d",&n);
      a[1][1]=getchar();
      for (int i=1;i<=n;i++)
       for (int j=1;j<=n+1;j++)
       {
         a[i][j]=getchar();
         if (a[i][j]=='E') m[i][j]=true;
         else if (a[i][j]=='H') m[i][j]=false;
       }
    //我们用dis[x1][y1][x2][y2][d1][d2]来表示两条路分别在x1,y1,面向d1,
    和在x2,y2,面向d2,从起点出发要到这个状态所需的最短指令。
      for (int i=1;i<=n;i++)
       for (int j=1;j<=n;j++)
        for (int i1=1;i1<=n;i1++)
         for (int j1=1;j1<=n;j1++)
          for (int u=1;u<=4;u++)
           for (int d=1;d<=4;d++)
           dis[i][j][i1][j1][u][d]=2147483647/2;//初始化
       dis[n][1][n][1][1][2]=0;
       ans=2147483647/2;
       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]);     
       cout<<ans<<endl;
    }
  • 相关阅读:
    HttpInvoker GET/POST方式
    maven命令
    java内存简单描述
    零零碎碎之SPU与SKU
    ZooKeeper的ACL权限
    ZooKeeper常用命令行操作
    Zookeeper基本数据模型
    ZooKeeper的安装及部署
    ZooKeeper原理及介绍
    Shell脚本编程(一)
  • 原文地址:https://www.cnblogs.com/2014nhc/p/6386580.html
Copyright © 2020-2023  润新知