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);
}
时间: 2024-10-19 10:00:48

Cow Navigation(USACO)的相关文章

奶牛接力 (Cow Relays, USACO 2007 Nov)

题目描述 For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout the pasture. Each trail connects two different intersections (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000), each

BZOJ 4761 Cow Navigation

一开始以为瞎jb写个IDA*就过了..然而并不是这样.(naive) 我的做法是dp[x1][y1][x2][y2][d1][d2],表示两头奶牛所在的位置和面朝的方向,然后直接spfa搞定. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define maxn 25 using namespace std; i

洞穴奶牛第一话 (Cave Cow 1, USACO 2004 Open)

题目大意: 状压dp #include<bits/stdc++.h> using namespace std; int dp[1<<15][105]; int maps[105][105],s[15]; int main() { int n,m,k,ans=0,res=0; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=k;i++) { scanf("%d",&s[i]

USACO 2.4

USACO 2.4.1 题解: 模拟. 用一个6维数组储存农夫与奶牛当前状态是否出现过,若出现过则表明出现循环,直接输出0,f[农夫x][农夫y][农夫方向][奶牛x][奶牛y][奶牛方向]. 最后注意转弯要算一步. 代码: /* ID:m1599491 PROB:ttwo LANG:C++ */ #include<cmath> #include<cstdio> #include<cstring> #include<iostream> using names

3298: [USACO 2011Open]cow checkers

3298: [USACO 2011Open]cow checkers Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 65  Solved: 26[Submit][Status][Discuss] Description 一天,Besssie准备和FJ挑战奶牛跳棋游戏.这个游戏上在一个M*N(1<=M<=1,000,000;1<=N<=1,000,000)的棋盘上, 这个棋盘上在(x,y)(0<=x棋盘的左下角是(0,0)坐标,

bzoj 3298: [USACO 2011Open]cow checkers -- 数学

3298: [USACO 2011Open]cow checkers Time Limit: 10 Sec  Memory Limit: 128 MB Description 一天,Besssie准备和FJ挑战奶牛跳棋游戏.这个游戏上在一个M*N(1<=M<=1,000,000;1<=N<=1,000,000)的棋盘上, 这个棋盘上在(x,y)(0<=x棋盘的左下角是(0,0)坐标,棋盘的右上角是坐标(M-1,N-1). Bessie每次都是第一个移动棋子,然后Bessie与

USACO 2.3 Cow Pedigrees

Cow Pedigrees Silviu Ganceanu -- 2003 Farmer John is considering purchasing a new herd of cows. In this new herd, each mother cow gives birth to two children. The relationships among the cows can easily be represented by one or more binary trees with

bzoj2581 [USACO 2012 Jan Gold] Cow Run【And-Or Tree】

传送门1:http://www.usaco.org/index.php?page=viewproblem2&cpid=110 传送门2:http://www.lydsy.com/JudgeOnline/problem.php?id=2581 这题我一看就知道自己不会了,只想了个O(2^n * 2 ^ n)即O(2 ^ 2n)的大暴力,也懒得打了,果断看solution. 看了之后惊呆了,看到了一种从未见过,闻所未闻的树叫做And-Or Tree,百度了一下,并没有官方中文翻译,姑且叫他"

[USACO 6.1.3] Cow XOR

题目大意 给出一个序列,求一个连续的子序列的异或和最大. 题解 先探究一下异或的性质. 1.可逆性: A XOR B XOR B = A; 2.满足结合律: (A XOR B) XOR C = A XOR (B XOR C); 利用以上两个性质有助于我们解题. 假设有一序列 A1,A2,A3......An-1,An ,可以得到另一序列 B1,B2,B3......Bn-1,Bn ,其中Bi表示A序列前i个元素的异或和. 所以,要求A序列从i到j的异或和就是Bj-Bi-1. 用这个结论就可以写一