hdu1072問題の解決策
悪夢
制限時間:2000/1000 MS(Java /その他)メモリ制限:65536/32768 K(Java /その他)
合計提出数:14457承認済み提出数:7027
問題の説明
イグナチオは昨夜悪夢を見ました。彼は時限爆弾のある迷路に身を置きました。迷路には出口があり、イグナチオは爆弾が爆発する前に迷路から抜け出す必要があります。爆弾の初期爆発時間は6分に設定されています。揺れによって爆弾が爆発するのを防ぐために、イグナチオはゆっくりと移動する必要がありました。つまり、ある領域から最も近い領域に移動する必要がありました(つまり、イグナチオが(x、y)に立っている場合、彼は(x + 1、 y)、(x-1、y)、(x、y + 1)、または(x、y-1)次の分で)1分かかります。迷路の一部のエリアには、爆弾リセット機器が含まれています。彼らは爆発時間を6分にリセットすることができました。
迷路のレイアウトとイグナチオの開始位置を考慮して、迷路から抜け出すことができるかどうか、もし可能であれば、迷路の出口を見つけるために使用する必要のある最小時間を出力するか、そうでない場合は-1を出力してください。
ここにいくつかのルールがあります:
- 迷路は2つの配列であると想定できます。
- イグネイシャスは毎分、最も近いエリアの1つにしか到達できず、国境から出てはいけません。もちろん、壁の上を歩くこともできません。
- イグナティウスが爆発時間が0になったときに出口に到達した場合、彼は迷路から抜け出すことができません。
- イグナティウスが爆発時間を0にしたときに爆弾休憩装置を含むエリアに到達した場合、爆弾をリセットするための装備を使用できません。
- Bomb-Reset-Equipmentは何度でも使用できます。必要に応じて、Ignatiusは迷路のどの領域にも何度でもアクセスできます。
- 爆発時間をリセットする時間は無視できます。つまり、IgnatiusがBomb-Rest-Equipmentを含むエリアに到達し、爆発時間が0より大きい場合、爆発時間は6にリセットされます。
入力
入力にはいくつかのテストケースが含まれています。入力の最初の行は、テストケースの数である単一の整数Tです。Tテストケースが続きます。
各テストケースは、迷路のサイズを示す2つの整数NおよびM(1 <= N、Mm = 8)で始まります。次に、N行が続き、各行にはM個の整数が含まれます。配列は迷路のレイアウトを示します。
迷路の異なるタイプのエリアを示す5つの整数があります:
0:エリアは壁であり、Ignatiusはその上を歩くべきではありません。
1:エリアには何も含まれていません。Ignatiusはその上を歩くことができます。
2:Ignatiusの開始位置。Ignatiusはこの位置からの脱出を開始します。
3:迷路の出口、イグナチオの目標位置。
4:エリアに爆弾リセット機器が含まれている場合、Ignatiusはこれらのエリアに歩くことで爆発時間を遅らせることができます。
出力
テストケースごとに、Ignatiusが迷路から抜け出すことができる場合は、彼が必要とする最小時間を出力する必要があります。そうでない場合は、-1を出力する必要があります。
サンプル入力
3
3 3
2 1 1
1 1 0
1 1 3
4 8
2 1 1 0 1 1 1 0
1 0 4 1 1 0 4 1
1 0 0 0 0 0 0 1
1 1 1 4 1 1 1 3
5 8
1 2 1 1 1 1 1 4
1 0 0 0 1 0 0 1
1 4 1 0 1 1 0 1
1 0 0 0 0 3 0 1
1 1 4 1 1 1 1 1
サンプル出力
4
-1
13
初心者の私はキューについてあまり知らないので、急いでbfsを使用しませんでした。この質問のdfの鍵は、残業を避けるために剪定することです。
以下はコードです
#include<iostream>
#include<iomanip>
#include<string>
#include<algorithm>
#define N 0x3f3f3f3f
using namespace std;
int a[10];
int ste[10][10];
int tim[10][10];
int map[10][10];
int dir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};//运用dir数组
int sx , sy , ex, ey;
int m, n;
int Min;
void dfs(int x , int y , int step, int len)
{
if(len<=0||step>Min) return;
if(map[x][y]==3)
{
if(step<Min)
Min=step;
return;
}
if(map[x][y]==4)
len=6;
if(step>=ste[x][y]&&len<=tim[x][y]) return;//关键的剪枝,判断这个点有没有被走过,再次走到这里时,与上一次进行比较,比较这次的效率与上一次的效率比有没有跟高。
ste[x][y]=step;
tim[x][y]=len;
int i, tx, ty;
for(i=0;i<4;i++)
{
tx=x+dir[i][0];
ty=y+dir[i][1];
if((tx>=0&&tx<n)&&(ty>=0&&ty<m))
{
if(map[tx][ty]!=0)
dfs(tx,ty,step+1,len-1);
}
}
return;
}
int main()
{
int T ;
cin>>T;
while(T--)
{
cin>>n>>m;
int i ,j;
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
cin>>map[i][j];
if(map[i][j]==2)
{
sx=i;sy=j;
}
if(map[i][j]==3)
{
ex=i;ey=j;
}
ste[i][j]=N;
tim[i][j]=0;
}
}
Min=N;
dfs(sx,sy,0,6);
if(Min==N)
cout<<-1;
else
cout<<Min;
cout<<endl;
}
return 0;
}