[BZOJ1644][Usaco2007 Oct]Obstacle Course 障碍训练课(spfa)

来源:互联网 发布:网络没有上传速度 编辑:程序博客网 时间:2024/05/18 09:03

题目描述

传送门

题解

看题之后一上手写了个dfs,结果发现tle了?
分析一下dfs的复杂度:如果不考虑最优化剪枝的话,是搜到终点再返回的。那么在最坏情况下,每个点的访问次数是指数级别的。
这不T就鬼了啊
改成spfa之后就A了。由于每一个点从四个方向走过来时的方案有可能是不同的,所以f(i,j,k)表示到(i,j)这个点,是从方向k走过来的最优值。也就相当于把一个点拆成了4个来做。
spfa的复杂度是O(kE)的,k一般为2或3,所以非常稳

代码

dfs(tle)

#include<iostream>#include<cstring>#include<cstdio>using namespace std;#define N 105#define inf 2000000000int n,sx,sy,tx,ty,ans;char a[N][N],s[N];int f[N][N][5];int dx[5]={0,0,0,1,-1};int dy[5]={0,1,-1,0,0};void dfs(int x,int y,int dep,int dir){    if (dep>=f[x][y][dir]||dep>=ans) return;    f[x][y][dir]=dep;    if (x==tx&&y==ty)    {        ans=min(ans,dep);        return;    }    for (int i=1;i<=4;++i)    {        int nx=x+dx[i],ny=y+dy[i];        if (nx<1||nx>n||ny<1||ny>n||a[nx][ny]=='x') continue;        if (!dir||dir==i) dfs(nx,ny,dep,i);        else dfs(nx,ny,dep+1,i);    }}int main(){    scanf("%d\n",&n);    for (int i=1;i<=n;++i)    {        gets(s);        for (int j=1;j<=n;++j)        {            a[i][j]=s[j-1];            if (s[j-1]=='A') sx=i,sy=j;            if (s[j-1]=='B') tx=i,ty=j;        }    }    ans=inf;    memset(f,127,sizeof(f));    f[sx][sy][1]=f[sx][sy][2]=f[sx][sy][3]=f[sx][sy][4]=0;    dfs(sx,sy,0,0);    printf("%d\n",ans);}

spfa

#include<iostream>#include<cstring>#include<cstdio>#include<queue>using namespace std;#define N 105int n,sx,sy,tx,ty,ans;char a[N][N],s[N];int f[N][N][4];bool vis[N][N][4];int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0};struct hp{int x,y,dir;};queue <hp> q;int Min(int a,int b,int c,int d){    if (a>b) a=b;    if (a>c) a=c;    if (a>d) a=d;    return a;}int main(){    scanf("%d\n",&n);    for (int i=1;i<=n;++i)    {        gets(s);        for (int j=1;j<=n;++j)        {            a[i][j]=s[j-1];            if (s[j-1]=='A') sx=i,sy=j;            if (s[j-1]=='B') tx=i,ty=j;        }    }    memset(f,127,sizeof(f));    f[sx][sy][0]=f[sx][sy][1]=f[sx][sy][2]=f[sx][sy][3]=0;    vis[sx][sy][0]=vis[sx][sy][1]=vis[sx][sy][2]=vis[sx][sy][3]=true;    q.push((hp){sx,sy,0});q.push((hp){sx,sy,1});q.push((hp){sx,sy,2});q.push((hp){sx,sy,3});    while (!q.empty())    {        hp now=q.front();q.pop();        vis[now.x][now.y][now.dir]=false;        for (int i=0;i<4;++i)        {            int x=now.x+dx[i],y=now.y+dy[i];            if (x<1||x>n||y<1||y>n||a[x][y]=='x') continue;            int len;            if (i==now.dir) len=0;            else len=1;            if (f[x][y][i]>f[now.x][now.y][now.dir]+len)            {                f[x][y][i]=f[now.x][now.y][now.dir]+len;                if (!vis[x][y][i]) vis[x][y][i]=true,q.push((hp){x,y,i});            }        }    }    ans=Min(f[tx][ty][0],f[tx][ty][1],f[tx][ty][2],f[tx][ty][3]);    printf("%d\n",ans);}

总结

①永远不要忘记分析时间复杂度。

0 0
原创粉丝点击