Cheese Aizu - 0558题解

チーズ ()

問題

今年も JOI 町のチーズ工場がチーズの生産を始め,ねずみが巣から顔を出した.JOI 町は東西南北に区画整理されていて,各区画は巣,チーズ工場,障害物,空き地のいずれかである.ねずみは巣から出発して全てのチーズ工場を訪れチーズを 1 個ずつ食べる.

この町には,N 個のチーズ工場があり,どの工場も1種類のチーズだけを生産している.チーズの硬さは工場によって異なっており,硬さ 1 から N までのチーズを生産するチーズ工場がちょうど 1 つずつある.

ねずみの最初の体力は 1 であり,チーズを 1 個食べるごとに体力が 1 増える.ただし,ねずみは自分の体力よりも硬いチーズを食べることはできない.

ねずみは,東西南北に隣り合う区画に 1 分で移動することができるが,障害物の区画には入ることができない.チーズ工場をチーズを食べずに通り過ぎることもできる.すべてのチーズを食べ終えるまでにかかる最短時間を求めるプログラムを書け.ただし,ねずみがチーズを食べるのにかかる時間は無視できる.

入力

入力は H+1 行ある.1 行目には 3 つの整数 H,W,N (1 ≤ H ≤ 1000,1 ≤ W ≤ 1000,1 ≤ N ≤ 9) がこの順に空白で区切られて書かれている.2 行目から H+1 行目までの各行には,'S','1', '2', ..., '9','X','.' からなる W 文字の文字列が書かれており,各々が各区画の状態を表している.北から i 番目,西から j 番目の区画を (i,j) と記述することにすると (1 ≤ i ≤ H, 1 ≤ j ≤ W),第 i+1 行目の j 番目の文字は,区画 (i,j) が巣である場合は 'S' となり,障害物である場合は 'X' となり,空き地である場合は '.' となり,硬さ 1, 2, ..., 9 のチーズを生産する工場である場合はそれぞれ '1', '2', ..., '9' となる.入力には巣と硬さ 1, 2, ..., N のチーズを生産する工場がそれぞれ 1 つずつある.他のマスは障害物または空き地であることが保証されている.ねずみは全てのチーズを食べられることが保証されている.

出力

すべてのチーズを食べ終えるまでにかかる最短時間(分)を表す整数を 1 行で出力せよ.

入出力例

入力例 1

3 3 1
S..
...
..1

出力例 1

4

入力例 2

4 5 2
.X..1
....X
.XX.S
.2.X.

出力例 2

12

入力例 3

10 10 9
.X...X.S.X
6..5X..X1X
...XXXX..X
X..9X...X.
8.X2X..X3X
...XX.X4..
XX....7X..
X..X..XX..
X...X.XX..
..X.......

出力例 3

91

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

思路

一开始想用深度优先搜索(可能是受了前面一题的影响,所以想用深搜),然后想一次深搜直接出结果,但是发现这样在标记走过的地方的时候比较麻烦,要给每一次从当前奶酪到达下一块奶酪的建立一个vis表。而且一开始不够自信,一直在怀疑是不是一定要从小到大(奶酪硬度)去吃奶酪,然后这个地方写判断的时候写得比较含糊(写了只有比当前体力小都可以选择吃或者不吃)。但是后来发现,吃奶酪一定要按照硬度从小到大的顺序去吃,如果要求最短路就不存在吃与不吃的选择,因为根据贪心的原理,每一次行走目标奶酪只有一个,如果第一次经过不吃就要等到第二次经过,这样明显不是最短路(因为多绕了一圈)。然后第二次写得时候就把每两个奶酪之间的行走分离开,然后求和,这样如何套模板就很明了了。

第一次写的程序(没有调出来,但是后来算了一下复杂度,觉得调出来应该也是TLE):

第二次写的程序:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#define maxn 1003
#define ll long long
using namespace std;
string ma[maxn];
int d[4][2]={1,0,0,-1,-1,0,0,1};
int m,n,num,a,b;
int vis[maxn][maxn];
ll ans;
struct node{
    int i,j,step;
};
node tar[13];
inline bool pd(int x, int y){
    return ( x >= 0 && y >= 0 && x < m && y < n && !vis[x][y] && ma[x][y] != 'X')?1:0;
}
int bfs(node a,node b){
    memset(vis,0,sizeof(vis));
    queue<node> q;
    q.push(a);
    vis[a.i][a.j] = 1;
    while(!q.empty()){
        node nd = q.front();
     //  cout<<"now i, j, step = "<<nd.i<<"  "<<nd.j<<"  "<<nd.step<<endl;
        nd.step++;
        q.pop();
        for(int i = 0; i < 4; ++i){
            int t =  nd.i + d[i][0], tt = nd.j + d[i][1];
            if( pd(t,tt) ){
              //  cout<<"loop i, j, step = "<<t<<"  "<<tt<<"  "<<nd.step<<endl;
                if( t == b.i && tt == b.j ) return nd.step;
                else{
                    node ndt;
                   // cout<<"before push back t, tt, i, j, step = "<<t<<"   "<<tt<<"   "<<ndt.i<<"   "<<ndt.j<<"  "<<ndt.step<<endl;
                    ndt.i = t, ndt.j = tt, ndt.step = nd.step, vis[t][tt]=1, q.push(ndt);
                   // cout<<"after push back i, j, step = "<<ndt.i<<"   "<<ndt.j<<"  "<<ndt.step<<endl;
                }
            }
        }
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>m>>n>>num;
    for(int i = 0; i < m; ++i){
        cin>>ma[i];
        for(int j = 0; j < n; ++j){
            if(ma[i][j] == 'S') tar[0].i = i, tar[0].j = j, tar[0].step = 0, ma[i][j] = '0';
            if( isdigit( ma[i][j] ) ){
                tar[ma[i][j] - 48].i = i, tar[ma[i][j] - 48].j = j, tar[ma[i][j] - 48].step = 0;
              //  cout<<"*************************"<<i<<" "<<j<<endl;
            }

        }
    }
//    for(int i = 0; i < num; ++i)
//        cout<<"tar[i].i = "<<tar[i].i<<"    ,tar[i].j = "<<tar[i].j<<"    ,tar[i].step = "<<tar[i].step<<endl;

    for(int i = 0; i < num; ++i){
      //  cout<<"i ,j = "<<i<<"   "<<i+1<<endl;
        ans += bfs(tar[i],tar[i+1]);
     //   cout<<"as = "<<as<<endl;
    }
    cout<<ans<<endl;

//     for(int i = 0; i < num; ++i)
//        cout<<"tar[i].i = "<<tar[i].i<<"    ,tar[i].j = "<<tar[i].j<<"    ,tar[i].step = "<<tar[i].step<<endl;
    return 0;
}

这个程序写的时候,遇到了几个bug,一个是存地图的时候存的是字符,遇到地图中的数字的时候存的也是字符,所以之后和数字的比较需要给数字这边加上48;还有就是一开始很顺地将这个bfs写了出来,但是忘记写vis了,导致死递归;然后还要记住判断边界条件;还有就是写模拟之前可以思考一下要模拟到什么程序,一般不会是完全的模拟题,肯定要化简一下的。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值