HDU 3681 Prison Break(状態圧縮dp+BFS)
28679 ワード
テーマリンク:http://acm.hdu.edu.cn/showproblem.php?pid=3681
先日時間をかけて見たテーマですが、書けませんでした。弱くて諦めました。今の後輩がこんなコードを書いてくれたとは思いませんでした。ここで彼の成果を借りて、よく勉強してください。
Sample Input
5
GDDSS
SSSFS
SYGYS
SGS YS
SSYSS
0
Sample Output
4
マトリックス(刑務所として)と電池を入れたロボットが刑務所にいます。 Fは出発点で、図中は一つしかなく、初期状態ではロボットはここで電池がいっぱいです。 Dは障害物ですので、歩いてはいけません。 Sはスペースです。マシンは自由に通過できます。 Gは充電ポイントで、一回しか充電できません。一回は電池がいっぱいになります。Gを通してSとして充電しないと、充電後GはSになります。 Y点はスイッチで、ロボットが通過し、かつ通過してSになります。 ロボットはYを全部通して、刑務所から逃げられます。これまでは一つの格子(上、下、左、右)だけで移動できました。そして一マスごとに電池の電池量を消耗しました。電池がないと移動できません。バッテリーがフル充電されている状態で、少なくとも何本の電気が彼を刑務所から脱出させることができますか?
この問題の考え方はそのデータから来ています。Y+Gの数は15より小さいです。ここからは状態圧縮DPが考えられます。
電気量の求め方は二分検索です。
全体図は明らかに処理しなければなりません。Y、Fはお互いに接続しなければなりません。接続しないと、明らかに無解です。逆に必ず解があります。Y,F,Gに対応する番号を、始点Fを0,Y,Gを順に番号付けし、YとGを2つの番号に分けると、次はゲートYと充電ポイントGの判断が容易になり、番号範囲を直接判断すれば良い。
次は各点に対する最短のショートを求めて、更に最短のショートを求めた後、Yを発見すれば、F間のある2点がつながりません。解がなければ、解がありません。
解があれば、状態圧縮DPを行い、各maxt(現在のバッテリのフルバッテリ量)に対して、途中でmaxtより大きいと更新できないので、いずれにしても判断して更新することができる。各Y点がすでにエルゴードされている場合、この状態で実行可能かどうかを判断し、可能であればTRUEに戻る。
コードは以下の通りです
先日時間をかけて見たテーマですが、書けませんでした。弱くて諦めました。今の後輩がこんなコードを書いてくれたとは思いませんでした。ここで彼の成果を借りて、よく勉強してください。
Sample Input
5
GDDSS
SSSFS
SYGYS
SGS YS
SSYSS
0
Sample Output
4
マトリックス(刑務所として)と電池を入れたロボットが刑務所にいます。
この問題の考え方はそのデータから来ています。Y+Gの数は15より小さいです。ここからは状態圧縮DPが考えられます。
電気量の求め方は二分検索です。
全体図は明らかに処理しなければなりません。Y、Fはお互いに接続しなければなりません。接続しないと、明らかに無解です。逆に必ず解があります。Y,F,Gに対応する番号を、始点Fを0,Y,Gを順に番号付けし、YとGを2つの番号に分けると、次はゲートYと充電ポイントGの判断が容易になり、番号範囲を直接判断すれば良い。
次は各点に対する最短のショートを求めて、更に最短のショートを求めた後、Yを発見すれば、F間のある2点がつながりません。解がなければ、解がありません。
解があれば、状態圧縮DPを行い、各maxt(現在のバッテリのフルバッテリ量)に対して、途中でmaxtより大きいと更新できないので、いずれにしても判断して更新することができる。各Y点がすでにエルゴードされている場合、この状態で実行可能かどうかを判断し、可能であればTRUEに戻る。
コードは以下の通りです
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<queue>
6 using namespace std;
7 const int INF=1<<29;
8 int as[600000];
9 void st()
10 {
11 int i, k=0;
12 for(i=1; i<600000; i*=2)
13 {
14 as[i]=++k;
15 }
16 }
17 struct Node
18 {
19 int x, y;
20 } nod[17];
21 struct POS
22 {
23 POS() {}
24 POS(int a,int b,int c)
25 {
26 x=a,y=b,now=c;
27 }
28 int x, y, now;
29 } pos;
30 int n, m, p, q, sx, sy;
31 int dis[17][17], dp[600000][17], the[17][17], num, ll;
32 char map[17][17];
33 bool ans;
34 void init() // Y,F,G
35 {
36 int i, j;
37 memset(the,-1,sizeof(the));
38 p=1;
39 for(i=0; i<n; i++)
40 {
41 for(j=0; j<m; j++)
42 {
43 if(map[i][j]=='F')
44 sx=i, sy=j;
45 if(map[i][j]=='Y')
46 {
47 nod[p].x=i, nod[p].y=j;
48 the[i][j]=p; //
49 p++;
50 }
51 }
52 }
53 q=p;
54 for(i=0; i<n; i++)
55 for(j=0; j<m; j++)
56 {
57 if(map[i][j]=='G')
58 {
59 nod[q].x=i, nod[q].y=j;
60 the[i][j]=q;
61 q++;
62 }
63 }
64 nod[0].x=sx, nod[0].y=sy;
65 the[sx][sy]=0;
66 for(i=0; i<q; i++)
67 for(j=0; j<q; j++)
68 {
69 if(i==j)
70 dis[i][j]=0;
71 else dis[i][j]=INF;
72 }
73 }
74 int dx[]= {1,0,-1,0};
75 int dy[]= {0,1,0,-1};
76 bool can(int x,int y)
77 {
78 if(x<0||x>=n||y<0||y>=m||map[x][y]=='D')
79 return false;
80 return true;
81 }
82 void bfs() //BFS Y,F,G
83 {
84 int i, j, nx, ny, x, y, now;
85 POS tmp;
86 bool vis[17][17];
87 for(i=0; i<q; i++)
88 {
89 memset(vis,0,sizeof(vis));
90 queue<POS> qq;
91 qq.push(POS(nod[i].x,nod[i].y,0));
92 while(!qq.empty())
93 {
94 tmp=qq.front();
95 qq.pop();
96 x=tmp.x, y=tmp.y, now=tmp.now;
97 for(j=0; j<4; j++)
98 {
99 nx=x+dx[j], ny=y+dy[j];
100 if(can(nx,ny)&&!vis[nx][ny])
101 {
102 if(the[nx][ny]!=-1)
103 dis[i][the[nx][ny]]=now+1;
104 vis[nx][ny]=true;
105 qq.push(POS(nx,ny,now+1));
106 }
107 }
108 }
109 }
110 for(i=0; i<p; i++)
111 for(j=0; j<p; j++)
112 if(dis[i][j]==INF) ans=false;
113 }
114 bool deal(int maxt) // DP
115 {
116 int i, j, k, tmp;
117 for(i=0; i<num; i++)
118 for(j=0; j<q; j++)
119 dp[i][j]=INF;
120 dp[0][0]=0;
121 int ed;
122 for(i=1; i<num; i++)
123 {
124 for(j=i; j>0; j-=j&(-j))
125 {
126 tmp=j&(-j);
127 ed=as[tmp];
128 for(k=0; k<q; k++)
129 if(dp[i^tmp][k]+dis[k][ed]<=maxt)
130 dp[i][ed]=min(dp[i^tmp][k]+dis[k][ed],dp[i][ed]);
131 if(ed>=p&&dp[i][ed]!=INF)
132 dp[i][ed]=0;
133 if(dp[i][ed]!=INF)
134 {
135 for(k=0; k<p; k++)
136 {
137 if(dp[i][ed]+dis[ed][k]<=maxt)
138 dp[i|(1<<(k-1))][k]=min(dp[i|(1<<(k-1))][k],dp[i][ed]+dis[ed][k]);
139 }
140 for(; k<q; k++)
141 {
142 if((1<<(k-1))&i) continue;
143 if(dp[i][ed]+dis[ed][k]<=maxt)
144 dp[i|(1<<(k-1))][k]=0;
145 }
146 }
147 }
148 if(i%ll==ll-1)
149 {
150 for(j=0; j<q; j++)
151 if(dp[i][j]<=maxt) return true;
152 }
153 }
154 return false;
155 }
156 int main()
157 {
158 int i, j, tmp, l, r;
159 st();
160 while(scanf("%d%d",&n,&m)!=EOF)
161 {
162 if(n==0&&m==0) break;
163 for(i=0; i<n; i++)
164 scanf("%s",map[i]);
165 init();
166 ans=true;
167 bfs();
168 num=1<<(q-1); //
169 l=1, r=300;
170 ll=1<<(p-1);
171 if(ans) //ans true ,Y F
172 {
173 while(l<r) //
174 {
175 m=(l+r)>>1;
176 if(deal(m))
177 r=m;
178 else l=m+1;
179 }
180 }
181 if(ans) printf("%d
",r);
182 else puts("-1");
183 }
184 return 0;
185 }