滑雪场建设{Gold题2}
【问题描述】
滑雪场的设计图是一个M*NM x N (1 <= M,N <= 100)的矩阵,每个格子里用一个字母R(表示粗糙)或者S(表示平整)。
比如:
RSRSSS
RSRSSS
RSRSSS
农民约翰的拖拉机每次可以将一块B*B (B <= M, B <= N)的区域全部标记B*B (B <= M, B <= N)的R或者S,他希望B能够尽量地大。一个格子可以被多次标记,下一次标记能够覆盖前一次标记,每个格子可以都至少被标记一次。
【文件输入】
第一行,两个用空格隔开的整数,分别表示M,N。
接下来2.. M+1行,每行一个M个符号,R或者S。表示用标记成的目标状态。
【文件输出】
共一行,一个整数,表示B的最大值。
【输入样例】
3 6
RSRSSS
RSRSSS
RSRSSS
【输出样例】
3
【样例说明】
首先将第1到第3列全部标记为R,然后第2到第4列全部标记为S,接下来将第3到5列全部标记为R,最后将第4到6列全部标记为S。
思路:每次考虑最后一步,能放上去的最大正方形边长是多少,然后将这块正方形上的每个点标记成任意(可R可S)以此类推下去,直到所有的点都被标记成了任意,运行结束。找最大正方形时用dp的思想来找f[i,j]:=min(min(f[i-1,j],f[i,j-1]),f[i-1,j-1])+1。可是这样的话还有最后一个点会超时,这时我们就需要使用一点点的小技巧,它叫卡时算法,略估计下大概运行几次能达到最优,然后卡时。下面上代码
1 var 2 a,f,g:array[-1..100,-1..100]of longint; //a为字母代号1表示R,2表示S,0表示任意;f,g分别表示以R和S为结尾的最大正方形 3 used:array[-1..100,-1..100]of boolean; //used表示该点是否已被处理 4 i,j,n,m,tx,ty,ans,posi,posj,flag,time,maxfg:longint; //flag记录剩余的没处理的点的个数;time用来计时 5 6 procedure openit; 7 begin 8 assign(input,'skicourse.in');assign(output,'skicourse.out'); 9 reset(input);rewrite(output); 10 end; 11 12 procedure closeit; 13 begin 14 close(input);close(output); 15 end; 16 17 procedure datain; //数据读入以及处理 18 var i,j:longint; 19 ch:char; 20 begin 21 readln(n,m); 22 flag:=n*m;ans:=10000000;time:=0; 23 //fillchar(used,sizeof(used),false); 24 //fillchar(f,sizeof(f),0); 25 //fillchar(g,sizeof(g),0); 26 for i:=1 to n do 27 begin 28 for j:=1 to m do 29 begin 30 read(ch); 31 if ch='R' then a[i,j]:=1 32 else a[i,j]:=2; 33 end; 34 readln; 35 end; 36 end; 37 38 function min(a,b:longint):longint; 39 begin 40 if a<b then min:=a 41 else min:=b; 42 end; 43 44 function max(a,b:longint):longint; 45 begin 46 if a>b then max:=a 47 else max:=b; 48 end; 49 50 51 begin 52 openit; 53 datain; 54 while flag>0 do 55 begin 56 for i:=tx to n do //处理出当前最大正方形的边长 57 for j:=ty to m do 58 begin 59 f[i,j]:=min(min(f[i-1,j],f[i,j-1]),f[i-1,j-1])+1; 60 g[i,j]:=min(min(g[i-1,j],g[i,j-1]),g[i-1,j-1])+1; 61 if a[i,j]=1 then g[i,j]:=0; 62 if a[i,j]=2 then f[i,j]:=0; 63 end; 64 posi:=1;posj:=1;maxfg:=0; 65 for i:=1 to n do //找出最大正方形所在的位置 66 for j:=1 to m do 67 if (max(f[i,j],g[i,j])>maxfg) and not used[i,j] then 68 begin 69 posi:=i;posj:=j; 70 maxfg:=max(f[i,j],g[i,j]); 71 end; 72 if maxfg<ans then ans:=maxfg; 73 used[posi,posj]:=true; 74 for i:=posi-maxfg+1 to posi do //修改原图 75 for j:=posj-maxfg+1 to posj do 76 if a[i,j]<>0 then 77 begin 78 dec(flag); 79 a[i,j]:=0; 80 end; 81 tx:=posi-maxfg+1;ty:=posj-maxfg+1; 82 inc(time); 83 if time=5000 then break; //卡时 84 end; 85 writeln(ans); 86 closeit; 87 end.