例题 7-9 万圣节后的早晨(The Morning after Halloween,Japan 2007,UVa1601)

原题链接:https://vjudge.net/problem/UVA-1601
分类:技巧优化
备注:双向广搜,经典题

记录状态很容易做,把每个位置计算一下二维数组转一维即可。
要注意的是不动也是一种状态,因此每个位置有1-5种选择的可能。优化的技巧就是利用’#'数量很多,因此只要记录空白相连的空白即可。
对于n=1和n=2要注意设置一个局外量,使得遍历不被干扰。

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int w,h,n;
int dis[2][260][260][260];
char g[20][20];
inline int cal(int row,int col){
    return row * w + col;
}
int st[3],ed[3];
vector<int>e[260];
inline void pushup(int row,int col){
    int x = cal(row,col);
    for(int i = 0; i < 4; i++){
        int row2 = row + dir[i][0];
        int col2 = col + dir[i][1];
        if(row2 < 0 || col2 < 0 || row2 >= h || col2 >= w)continue;
        if(g[row2][col2] == '#')continue;
        e[x].push_back(cal(row2,col2));
    }
}
struct node{
    int pos[3];
    node(int a, int b, int c){
        pos[0] = a; pos[1] = b; pos[2] = c;
    }
};
inline void nxtStp(queue<node>& q, int o, int& ans){
    if(q.empty())return;
    node u = q.front(); q.pop();
    int a = u.pos[0],b = u.pos[1],c = u.pos[2];
    if(dis[o^1][a][b][c] != -1){
        ans = min(ans,dis[o][a][b][c] + dis[o^1][a][b][c]);
    }
    for(int i = 0; i < e[a].size(); i++){
        int a2 = e[a][i];
        for(int j = 0; j < e[b].size(); j++){
            int b2 = e[b][j];
            if(a2 == b2 || (a2 == b && b2 == a))continue;
            for(int k = 0; k < e[c].size(); k++){
                int c2 = e[c][k];
                if(a2 == c2 || (a2 == c && c2 == a))continue;
                if(b2 == c2 || (b2 == c && c2 == b))continue;
                if(dis[o][a2][b2][c2] != -1)continue;
                dis[o][a2][b2][c2] = dis[o][a][b][c] + 1;
                q.push(node(a2,b2,c2));
            }
        }
    }
}
int main(void){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(scanf("%d %d %d", &w, &h, &n) && (w || h || n)){
        memset(dis,-1,sizeof(dis));
        for(int i = 0; i < 260; i++)e[i].clear(),e[i].push_back(i);
        for(int i = 0; i < 3; i++)st[i] = ed[i] = 0;
        for(int i = 0; i < h; i++){
            getchar();
            for(int j = 0; j < w; j++){
                scanf("%c",&g[i][j]);
                if(islower(g[i][j]))st[g[i][j]-'a'] = cal(i,j);
                if(isupper(g[i][j]))ed[g[i][j]-'A'] = cal(i,j);
            }
        }
        for(int i = 0; i < h; i++){
            for(int j = 0; j < w; j++){
                pushup(i,j);
            }
        }
        if(n<=2)st[2]=ed[2]=257;
        if(n==1)st[1]=ed[1]=258;
        queue<node>q[2];
        q[0].push(node(st[0],st[1],st[2]));
        dis[0][st[0]][st[1]][st[2]] = 0;
        q[1].push(node(ed[0],ed[1],ed[2]));
        dis[1][ed[0]][ed[1]][ed[2]] = 0;
        int ans = inf, o = 0 ;
        while(!q[0].empty()&&!q[1].empty()){
            nxtStp(q[o], o, ans);
            o = o^1;
            if(ans!=inf)break;
        }
        printf("%d\n",ans);
    }   
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JILIN.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值