HDU 3912 Turn Right + HDU 1254 推箱子 + HDU 1983 Kaitou Kid - The Phantom Thief (2)

来源:互联网 发布:linux 查看几个cpu 编辑:程序博客网 时间:2024/05/16 07:19

http://acm.hdu.edu.cn/showproblem.php?pid=3912
这题应该算是个模拟题。题意大概是这样的:
一个n*m的网格,在第一行有个入口,第n行有个出口。然后人在里面行走必须满足如下条件:如果能向右走,就向右走,若不能向右走就向前走,如果不能向前走就向左走,如果不能向左走就像后走。题目中明确规定了可以保证从入口走到出口。问你的是:先从入口走到出口,再从出口走到入口,问能否遍历所有的网格。

因为题目所给的网格是有墙的。开始傻傻的我竟然用两个三维数组来存墙的位置,结果TLE,后来去食堂吃饭想起来可以用结构体存啊(too_young_too_simple),于是回来敲,结果TLE。次奥,当时就无语了。后来还是在巍神的启发下用了vis[4][N][N],这个数组的作用是存该点的可以走的方向 ===
我感受到了智商的压制 (大哭。。/(ㄒoㄒ)/~~

于是敲了代码,结果WA了。原因是有个地方没有注意到,我dfs的终止条件是当 (x==n&&y==ed)就退出,忽略了这种情况:
这里写图片描述
我的代码是只要到达这个网格就退出(红线),事实证明它还要往前走一步(黑线)。所以我在当先的地图上加了两个多余的网格。

反思: 谢谢巍神的 vis[4][N][N] 数组,以后长点心眼。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define  mset(x,y)  memset(x,y,sizeof(x));using namespace std;const int N = 500+10;int n,m,st,ed;bool Map[N][N];int cnt;bool vis[4][N][N];//奇妙的数组int dir[4][2]={1,0,0,-1,-1,0,0,1};bool check(int x,int y,int xx,int yy,int i){    if(xx==0&&yy==st+1) return true;    if(xx==n+1&&yy==ed+1) return true;    if(xx<1||xx>n) return false;    if(yy<1||yy>m) return false;    if(!vis[i][x][y]) return false;//一句话判掉不符合情况的    return true;}void work(int x,int y,int aim,int op){    if(op==1&&x==n+1&&y==ed+1) return;//注意是 (n+1行    if(op==2&&x==0&&y==st+1) return;//递归终止条件变了    int tmp,xx,yy;    for(int i=0;i<4;i++)    {   //本题的模拟关键处        if(i==0) tmp=(aim+1)%4;        else if(i==1) tmp=aim;        else if(i==2) tmp=((aim-1)%4+4)%4;        else tmp=(aim+2)%4;        xx=x+dir[tmp][0];        yy=y+dir[tmp][1];        if(!check(x,y,xx,yy,tmp)) continue;        if(Map[xx][yy])  cnt--,Map[xx][yy]=false;        break;    }    work(xx,yy,tmp,op);    return;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        mset(vis,true);        mset(Map,true);        scanf("%d%d%d%d",&n,&m,&st,&ed);        for(int i=1;i<=2*n-1;i++)        {            int x;            if(i%2)            {                for(int j=1;j<m;j++)                {                    scanf("%d",&x);                    if(x==1) vis[3][(i+1)/2][j]=vis[1][(i+1)/2][j+1]=false;//!!!                }            }            else            {                for(int j=1;j<=m;j++)                {                    scanf("%d",&x);                    if(x==1) vis[0][i/2][j]=vis[2][i/2+1][j]=false;//!!!                }            }        }        cnt=n*m;        Map[1][st+1]=Map[0][st+1]=Map[n+1][ed+1]=false;        cnt--;        work(1,st+1,0,1);        work(n,ed+1,2,2);        puts(cnt==0?"YES":"NO");    }    return 0;}

http://acm.hdu.edu.cn/showproblem.php?pid=1254

题意不用说,以前玩过的小游戏。
需要注意的地方:

  • 人可以走箱子的终点,也就是 3 这个位置
  • 判断箱子是否可以推的前提是 人是否能到达箱子的另外一个方向
  • 箱子要推的地方不能是墙,而且箱子可以经过一个地方两次
  • 标记的时候用vis[4][N][N]标记人的位置和推箱子的方向(因为箱子可以到达一个地方两次,显然标记箱子没用;标记人的地方和在这里人往哪个方向推箱子)
  • 推箱子的时候箱子前进一步但是人不会动
  • 还有就是要细心耐心的debug…
#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <queue>using namespace std;const int N =  10;int Map[N][N];bool vis[4][N][N];struct Node{    int posx,posy;//当前箱子的位置    int xx,yy;//当前人的位置    int cnt;};int n,m;int dir[4][2]={0,1,1,0,0,-1,-1,0};struct Node1{    int x;int y;};bool check(int x,int y){    if(x<1||x>n) return false;    if(y<1||y>m) return false;    if(Map[x][y]==1) return false;    return true;}bool judge(int x,int y,int aimx,int aimy,int posx,int posy)//判断人是否可以到达箱子的另一端{    bool vvis[N][N];    memset(vvis,true,sizeof(vvis));    Node1 now,next;    queue<Node1> que;    now.x=x;now.y=y;    vvis[x][y]=false;    que.push(now);    while(!que.empty())    {        now=que.front(); que.pop();        if(now.x==aimx &&now.y==aimy) return true;        for(int i=0;i<4;i++)        {            next.x=now.x+dir[i][0];            next.y=now.y+dir[i][1];            if(!check(next.x,next.y)) continue;            if(!vvis[next.x][next.y]) continue;            if(next.x==posx&&next.y==posy) continue;            vvis[next.x][next.y]=false;            que.push(next);        }    }    return false;}int bfs(int x1,int y1,int x2,int y2){    Node now,next;    queue<Node> que;    now.posx=x1;now.posy=y1;    now.xx=x2; now.yy=y2;    now.cnt=0;    que.push(now);    while(!que.empty())    {        now=que.front();        que.pop();        if(Map[now.posx][now.posy]==3) return now.cnt;        for(int i=0;i<4;i++)        {            int aimx=now.posx-dir[i][0];            int aimy=now.posy-dir[i][1];            if(!judge(now.xx,now.yy,aimx,aimy,now.posx,now.posy)) continue;            if(!vis[i][aimx][aimy]) continue;            next.posx=now.posx+dir[i][0];            next.posy=now.posy+dir[i][1];            if(!check(next.posx,next.posy)) continue;            next.xx=aimx; next.yy=aimy;//更新人的位置            vis[i][aimx][aimy]=false;            next.cnt=now.cnt+1;            que.push(next);        }    }    return -1;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        int posx=1,posy=1,xx=1,yy=1;        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            scanf("%d",&Map[i][j]);            if(Map[i][j]==2) posx=i,posy=j;            if(Map[i][j]==4) xx=i,yy=j;        }        memset(vis,true,sizeof(vis));        printf("%d\n",bfs(posx,posy,xx,yy));    }    return 0;}

http://acm.hdu.edu.cn/showproblem.php?pid=1983
题意很简单,全是中文。
这题让我惊讶的地方就是 暴力啊暴力啊暴力啊,从未见过如此暴力的题目。
因为要封锁的地方绝对是<=4的,所以暴力从小到大枚举可能封锁的区域,直到满足情况为止。
暴力出奇迹:既然时间给的是5秒就不要怂,暴力搞起来,被吓到了

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>using namespace std;const int N =10;char Map[N][N];int n,m,sx,sy,k;struct Node{    int x,y,cnt;    int has;};int dir[4][2]={0,1,1,0,0,-1,-1,0};bool bfs(){    bool vis[10][10][2];    memset(vis,true,sizeof(vis));    Node now,next;    queue<Node> que;    now.x=sx; now.y=sy;    now.cnt=0;    now.has=0;    vis[now.x][now.y][0]=false;    que.push(now);    while(!que.empty())    {        now=que.front();        que.pop();        if( Map[now.x][now.y]=='E' && now.has &&now.cnt<=k ) return false;        if(now.cnt>k) continue;        for(int i=0;i<4;i++)        {            next.x=now.x+dir[i][0];            next.y=now.y+dir[i][1];            if(next.x<1||next.x>n||next.y<1||next.y>m) continue;            if(!vis[next.x][next.y][now.has]||Map[next.x][next.y]=='#') continue;            next.has=now.has;            if(Map[next.x][next.y]=='J') next.has=1;            vis[next.x][next.y][next.has]=false;            next.cnt=now.cnt+1;            que.push(next);        }    }    return true;}bool dfs(int t){    if(!t) return bfs();    for(int i=1;i<=n;i++)        for(int j=1;j<=m;j++)        {            if(Map[i][j]=='#'||Map[i][j]=='E') continue;            char op=Map[i][j];            Map[i][j]='#';            if(dfs(t-1)) return true;            Map[i][j]=op;        }    return false;}int main(){    int T;    scanf("%d",&T);    while(T--)    {       scanf("%d %d %d",&n,&m,&k);       for(int i=1;i<=n;i++)          for(int j=1;j<=m;j++)          {              scanf(" %c",&Map[i][j]);              if(Map[i][j]=='S') sx=i,sy=j;          }       bool flag=false;       for(int i=0;i<4;i++)       {           if(dfs(i)) { flag=true;printf("%d\n",i);break;}       }       if(!flag) printf("4\n");    }    return 0;}

That’s all :)

0 0