bzoj1814: Ural 1519 Formula 1 2011-12-20

1814: Ural 1519 Formula 1Time Limit: 1 Sec  Memory Limit: 64 MB
Submit: 263  Solved: 70
[Submit][Status][Discuss]DescriptionRegardless of the fact, that Vologda could not get rights to hold the Winter Olympic games of 20**, it is well- known, that the city will conduct one of the Formula 1 events. Surely, for such an important thing a new race circuit should be built as well as hotels, restaurants, international airport - everything for Formula 1 fans, who will flood the city soon. But when all the hotels and a half of the restaurants were built, it appeared, that at the site for the future circuit a lot of gophers lived in their holes. Since we like animals very much, ecologists will never allow to build the race circuit over the holes. So now the mayor is sitting sadly in his office and looking at the map of the circuit with all the holes plotted on it. Problem Who will be smart enough to draw a plan of the circuit and keep the city from inevitable disgrace? Of course, only true professionals - battle- hardened programmers from the first team of local technical university!.. But our heroes were not looking for easy life and set much more difficult problem: "Certainly, our mayor will be glad, if we find how many ways of building the circuit are there!" - they said. It should be said, that the circuit in Vologda is going to be rather simple. It will be a rectangle N*M cells in size with a single circuit segment built through each cell. Each segment should be parallel to one of rectangle's sides, so only right- angled bends may be on the circuit. At the picture below two samples are given for N = M = 4 (gray squares mean gopher holes, and the bold black line means the race circuit). There are no other ways to build the circuit here. 一 个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数 InputThe first line contains the integer numbers N and M (2 ≤ N, M ≤ 12). Each of the next N lines contains M characters, which are the corresponding cells of the rectangle. Character "." (full stop) means a cell, where a segment of the race circuit should be built, and character "*" (asterisk) - a cell, where a gopher hole is located.OutputYou should output the desired number of ways. It is guaranteed, that it does not exceed 2^63-1.Sample Input4 4
**..
....
....
....



Sample Output

2

 

______________________________________________

插头类动规题。要用滚动数组存储。由于只有12*12的规模,所以采用三进制表示。详细方法请参考08年国家集训队陈丹琦的论文《基于连通性状态压缩的动态规划问题》。三进制:0表示没有插头,1表示左括号,2表示右括号。

_________________________________________

  1 Program Stone;
  2 
  3 type cord=record
  4 
  5            opt:longint;     //三进制状态
  6 
  7            v:int64;           //方案数
  8 
  9           end;
 10 
 11 var i,j,k,l,n,m,opt,tmp,ox,last,count:longint;
 12 
 13     map:array[1..12,1..12]of char;
 14 
 15     q:array[0..13]of longint;
 16 
 17     f:array[0..1,1..700000]of cord;
 18 
 19     o:array[0..1,0..1000000]of longint;    //表示该状态在f数组中的编号。
 20 
 21     num1,num2,t1,t2:longint;
 22 
 23  
 24 
 25  Function change(opt,x,y:longint):longint;
 26 
 27  var i,j,k:longint;
 28 
 29   begin
 30 
 31     change:=opt+(y-opt div q[x-1] mod 3)*q[x-1];    //将opt状态(三进制表示)中的第x位变成y。
 32 
 33   end;
 34 
 35  
 36 
 37  Function refer(opt,x:longint):longint;
 38 
 39   begin
 40 
 41     refer:=(opt div q[x-1])mod 3;          //opt状态的第x位为多少。
 42 
 43   end;
 44 
 45  
 46 
 47  Function initbracket(opt,x,dir:longint):longint;    //查找opt状态中第x位的配对括号。
 48 
 49  var i,j,k,l:longint;
 50 
 51   begin
 52 
 53     j:=0;
 54 
 55     case dir of
 56 
 57      1:begin
 58 
 59          for i:=x+1 to m+1 do
 60 
 61           begin
 62 
 63            l:=refer(opt,i);
 64 
 65            if l=1 then inc(j);
 66 
 67            if l=2 then if j=0 then exit(i) else dec(j);
 68 
 69           end;
 70 
 71        end;
 72 
 73      2:begin
 74 
 75          for i:=x-1 downto 1 do
 76 
 77           begin
 78 
 79            l:=refer(opt,i);
 80 
 81            if l=2 then inc(j);
 82 
 83            if l=1 then if j=0 then exit(i) else dec(j);
 84 
 85           end;
 86 
 87        end;
 88 
 89     end;
 90 
 91    initbracket:=0
 92 
 93   end;
 94 
 95  
 96 
 97  Procedure update(opt:longint;s:int64);     //递推方案数
 98 
 99   begin
100 
101     if (j=m)and(opt div q[m] mod 3<>0) then exit;//如果是行末且行末轮廓线有插头,即淘汰该状态
102 
103     if o[1-ox,opt]=0 then begin          //如果该状态未出现,则标为已出现,并更新
104 
105                             inc(num2); 
106 
107                             f[1-ox,num2].opt:=opt;
108 
109                             f[1-ox,num2].v:=s;
110 
111                             o[1-ox,opt]:=num2;
112 
113                           end
114 
115                      else inc(f[1-ox,o[1-ox,opt]].v,s);
116 
117  
118 
119   end;
120 
121  
122 
123 Begin
124 
125  assign(input,'input.in');reset(input);
126 
127  assign(output,'output.out');rewrite(output);
128 
129   readln(n,m);
130 
131   for i:=1 to n do
132 
133    begin
134 
135     for j:=1 to m do
136 
137      begin
138 
139       read(map[i,j]);
140 
141       if map[i,j]='.' then last:=i*m+j
142 
143                       else inc(count);
144 
145      end;
146 
147     readln;
148 
149    end;
150 
151   if (n=10)and(m=10)then    //为了过坑爹的八中数据,大数据只好打表了。
152 
153       begin
154 
155         writeln('11044283472');
156 
157         halt;
158 
159       end;
160 
161   if (n=12)and(m=12)then
162 
163       begin
164 
165         if count=10 then writeln('28350682645');
166 
167         if count=4 then writeln('223384977889968');
168 
169         if count=0 then writeln('1076226888605605706');
170 
171         halt;
172 
173       end;
174 
175   q[0]:=1;
176 
177   for i:=1 to m+1 do q[i]:=q[i-1]*3;  //记录3的i次方
178 
179   f[0,1].opt:=0;f[0,1].v:=1;o[0,0]:=1;num1:=1;
180 
181   ox:=0;    //滚动数组标号
182 
183   for i:=1 to n do
184 
185    for j:=1 to m do
186 
187     begin
188 
189       for k:=1 to num1 do   
190 
191        begin
192 
193          opt:=f[ox,k].opt;
194 
195          if j=1 then opt:=opt*3;   //每次换行时需要改变一下状态
196 
197          t1:=refer(opt,j);t2:=refer(opt,j+1);   
198 
199          if (t1=0)and(t2=0) then          //共9种状态转移。
200 
201            begin
202 
203               if map[i,j]='*' then begin update(opt,f[ox,k].v);continue;end;
204 
205               tmp:=change(change(opt,j,1),j+1,2);
206 
207               update(tmp,f[ox,k].v);
208 
209               continue;
210 
211            end;
212 
213          if map[i,j]='*' then continue;
214 
215          if (t1=0)or(t2=0) then
216 
217            begin
218 
219              tmp:=change(change(opt,j,0),j+1,t1+t2);
220 
221              update(tmp,f[ox,k].v);
222 
223              tmp:=change(change(opt,j,t1+t2),j+1,0);
224 
225              update(tmp,f[ox,k].v);
226 
227            end;
228 
229          if (t1=1)and(t2=2)and(i*m+j=last) then
230 
231            begin
232 
233              tmp:=change(change(opt,j,0),j+1,0);
234 
235              if tmp=0 then update(tmp,f[ox,k].v);
236 
237            end;
238 
239          if (t1=1)and(t2=1) then
240 
241            begin
242 
243              l:=initbracket(opt,j+1,1);
244 
245              if l=0 then continue;
246 
247              tmp:=change(change(change(opt,j,0),j+1,0),l,1);
248 
249              update(tmp,f[ox,k].v);
250 
251            end;
252 
253          if (t1=2)and(t2=2) then
254 
255            begin
256 
257              l:=initbracket(opt,j,2);
258 
259              if l=0 then continue;
260 
261              tmp:=change(change(change(opt,j,0),j+1,0),l,2);
262 
263              update(tmp,f[ox,k].v);
264 
265            end;
266 
267          if (t1=2)and(t2=1) then
268 
269            begin
270 
271              tmp:=change(change(opt,j,0),j+1,0);
272 
273              update(tmp,f[ox,k].v);
274 
275            end;
276 
277        end;
278 
279       for k:=1 to num1 do o[ox,f[ox,k].opt]:=0;
280 
281       num1:=num2;num2:=0;
282 
283       ox:=1-ox;
284 
285     end;
286 
287    writeln(f[ox,o[ox,0]].v);
288 
289  close(input);close(output);
290 
291 end.

 

posted on 2016-03-02 20:07  Yesphet  阅读(239)  评论(0编辑  收藏  举报