USACO 2014 JAN滑雪场建设{Gold题2}

滑雪场建设{Gold2}

【问题描述】

滑雪场的设计图是一个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.
原文地址:https://www.cnblogs.com/p0226/p/4076405.html