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 :)
- HDU 3912 Turn Right + HDU 1254 推箱子 + HDU 1983 Kaitou Kid - The Phantom Thief (2)
- hdu 1983 Kaitou Kid - The Phantom Thief (2) DFS + BFS
- hdu 1983 Kaitou Kid - The Phantom Thief (2) (DFS+BFS)
- HDU 1983 - Kaitou Kid - The Phantom Thief (2)
- HDU 1983 Kaitou Kid - The Phantom Thief (2)
- HDU 1983 Kaitou Kid - The Phantom Thief (2)
- hdu 1983 Kaitou Kid - The Phantom Thief (2)
- HDU 1983 Kaitou Kid - The Phantom Thief (2)
- hdu 1983 Kaitou Kid - The Phantom Thief (2)(bfs+dfs)
- hdu 1983 Kaitou Kid - The Phantom Thief (2)
- hdu 1983 Kaitou Kid - The Phantom Thief (2)
- 【DFS+BFS】hdu 1983 Kaitou Kid - The Phantom Thief (2)(迷宫)
- HDU 1983 Kaitou Kid - The Phantom Thief (2)(DFS套BFS)
- hdu 1983 Kaitou Kid - The Phantom Thief (2)【Bfs+暴力枚举】
- HDU 1983 Kaitou Kid - The Phantom Thief (2)(DFS+BFS)
- hdu 1982 Kaitou Kid - The Phantom Thief (1) (水。。)
- hdu 1982 Kaitou Kid - The Phantom Thief (1)
- hdu 1982——Kaitou Kid - The Phantom Thief (1)
- Linux-命令-crontab
- 新入行程序员应知的十个秘密
- swift学习1 oc swift混编
- 企业应用开发面临的问题以及思考
- 大项目源码分析方法总结
- HDU 3912 Turn Right + HDU 1254 推箱子 + HDU 1983 Kaitou Kid - The Phantom Thief (2)
- [网络流24题] 17 运输问题(网络费用流量,最小费用最大流)
- Cordova android框架详解
- leetcode Balanced Binary Tree 题解
- eclipse配置tomcat,以及部署项目到tomcat(解决项目部署后,webapps中无项目文件问题)
- bootstrap css样式起步
- 增加eclipse的内存
- ios8 UITableView设置 setSeparatorInset:UIEdgeInsetsZero不起作用的解决办法
- Java线程-----------线程安全与不安全与线程同步synchronized和volatile