[uva P1601] The Morning after Halloween

本文详细解析了UVA P1601题目——The Morning after Halloween,介绍了使用双向BFS算法解决该问题的方法,通过构建隐式图避免冗余判断,实现了对三个小鬼在迷宫中移动的高效模拟。

[uva P1601] The Morning after Halloween

题目链接

 

非常经典的一道题目,lrj的书上也有(貌似是紫书?)。

其实这题看起来就比较麻烦。。

首先要保证小鬼不能相遇,也不能互相穿过。

可以用一个vis[][][]数组来表示三个小鬼的当前处于位置是否已经访问,

dis[][][]表示到某个状态是最小步数,用short存,可以卡住空间。

但是这样效率不高。注意到每四个格子里面至少有一个‘#’,所以我们可以把原来的网格图建一个隐式图,就可以避开很多冗余判断。

为了提高效率,我用了双向bfs。

其实就是在原来bfs基础上加点东西,代码量还是有点长的。

据说我的空间还是很大,在某些oj上会被卡。。所以还需要更优秀的标记。

code:

  1 %:pragma GCC optimize(2)
  2 #include<bits/stdc++.h>
  3 #define idx(i,j) ((i)*m+(j))
  4 #define Ms(a,x) memset(a,x,sizeof a)
  5 using namespace std;
  6 const int N=18,P=260,fl[5][2]={{0,1},{-1,0},{1,0},{0,-1},{0,0}};
  7 struct sta {int p[4],lays;}cur,nxt;
  8 int n,m,t,G[P][5],C[P]; char ch,a[N][N];
  9 short vis[P][P][P],dis[P][P][P];
 10 queue <sta> Q[2];
 11 inline char read() {
 12     ch=getchar();
 13     while (ch!=' '&&ch!='#'&&!isalpha(ch)) ch=getchar();
 14     return ch;
 15 }
 16 void add(int u,int v) {G[u][C[u]++]=v;}
 17 bool jug(int x,int y) {
 18     if (x<0||x>n-1||y<0||y>m-1) return 0;
 19     return a[x][y]!='#';
 20 }
 21 int update(int id) {
 22     if (vis[nxt.p[0]][nxt.p[1]][nxt.p[2]]==-1) {
 23         vis[nxt.p[0]][nxt.p[1]][nxt.p[2]]=id;
 24         dis[nxt.p[0]][nxt.p[1]][nxt.p[2]]=nxt.lays;
 25         Q[id].push(nxt);
 26         return -1;
 27     }else if (vis[nxt.p[0]][nxt.p[1]][nxt.p[2]]==1-id)
 28         return nxt.lays+dis[nxt.p[0]][nxt.p[1]][nxt.p[2]];
 29     return -1;
 30 }
 31 int bfs(int id,int s) {
 32     while (!Q[id].empty()) {
 33         cur=Q[id].front();
 34         if (cur.lays!=s) return -1;
 35         Q[id].pop();
 36         if (t==1) {
 37             nxt=cur,nxt.lays=s+1;
 38             for (int i=0,s1=C[cur.p[0]]; i<s1; i++) {
 39                 nxt.p[0]=G[cur.p[0]][i];
 40                 int re=update(id);
 41                 if (~re) return re;
 42             }
 43         }else
 44         if (t==2) {
 45             nxt=cur,nxt.lays=s+1;
 46             for (int i=0,s1=C[cur.p[0]]; i<s1; i++) {
 47                 nxt.p[0]=G[cur.p[0]][i];
 48                 for (int j=0,s2=C[cur.p[1]]; j<s2; j++) {
 49                     nxt.p[1]=G[cur.p[1]][j];
 50                     if (nxt.p[1]==nxt.p[0]) continue;
 51                     if (nxt.p[0]==cur.p[1]&&nxt.p[1]==cur.p[0]) continue;
 52                     int re=update(id);
 53                     if (~re) return re;
 54                 }
 55             }
 56         }else
 57         if (t==3) {
 58             nxt=cur,nxt.lays=s+1;
 59             for (int i=0,s1=C[cur.p[0]]; i<s1; i++) {
 60                 nxt.p[0]=G[cur.p[0]][i];
 61                 for (int j=0,s2=C[cur.p[1]]; j<s2; j++) {
 62                     nxt.p[1]=G[cur.p[1]][j];
 63                     if (nxt.p[1]==nxt.p[0]) continue;
 64                     if (nxt.p[0]==cur.p[1]&&nxt.p[1]==cur.p[0]) continue;
 65                     for (int k=0,s3=C[cur.p[2]]; k<s3; k++) {
 66                         nxt.p[2]=G[cur.p[2]][k];
 67                         if (nxt.p[0]==nxt.p[2]||nxt.p[1]==nxt.p[2]) continue;
 68                         if (nxt.p[0]==cur.p[2]&&nxt.p[2]==cur.p[0]) continue;
 69                         if (nxt.p[1]==cur.p[2]&&nxt.p[2]==cur.p[1]) continue;
 70                         int re=update(id);
 71                         if (~re) return re;
 72                     }
 73                 }
 74             }
 75         }
 76     }
 77     return -1;
 78 }
 79 int double_bfs() {
 80     while (!Q[0].empty()) Q[0].pop();
 81     while (!Q[1].empty()) Q[1].pop();
 82     Ms(vis,-1),Ms(dis,63);
 83     for (int i=0; i<3; i++) cur.p[i]=256; cur.lays=0;
 84     for (int i=0; i<n; i++)
 85         for (int j=0; j<m; j++)
 86             if (isupper(a[i][j])) cur.p[a[i][j]-'A']=idx(i,j);
 87     Q[0].push(cur),vis[cur.p[0]][cur.p[1]][cur.p[2]]=0;
 88     for (int i=0; i<3; i++) cur.p[i]=256; cur.lays=0;
 89     for (int i=0; i<n; i++)
 90         for (int j=0; j<m; j++)
 91             if (islower(a[i][j])) cur.p[a[i][j]-'a']=idx(i,j);
 92     Q[1].push(cur),vis[cur.p[0]][cur.p[1]][cur.p[2]]=1;
 93     for (int st=0; !Q[0].empty()&&!Q[1].empty(); st++) {
 94         int tag0=bfs(0,st),tag1=bfs(1,st);
 95         if (~tag0) return tag0;
 96         if (~tag1) return tag1;
 97     }
 98     return 233666;
 99 }
100 int main() {
101     while (scanf("%d%d%d",&m,&n,&t)!=EOF,n|m|t) {
102         for (int i=0; i<n; i++)
103             for (int j=0; j<m; j++)
104                 a[i][j]=read(),C[idx(i,j)]=0;
105         for (int i=0; i<n; i++)
106             for (int j=0; j<m; j++)
107                 for (int k=0; k<5; k++) {
108                     if (!jug(i+fl[k][0],j+fl[k][1])) continue;
109                     add(idx(i,j),idx(i+fl[k][0],j+fl[k][1]));
110                 }
111         printf("%d\n",double_bfs());
112     }
113     return 0;
114 }
View Code

 

转载于:https://www.cnblogs.com/whc200305/p/7692426.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值