积木游戏 纪中 1440 类dp 预处理

Description

  在一个N*N的区域玩积木游戏,每个单元格正好跟积木的底面相等,每个单元格里放有若干个积木,Alice想重新摆放积木,使得每个单元格最多只能放一个积木,并且所有积木正好形成一个矩形。
  把一个积木从一个位置移到另一个位置称为一次操作。
  给出初始状态,编程计算最少需要多少次操作才能达到上述要求。

Input

  第一行包含两个整数N和M(1<=N<=100,1<=M<=N^2),表示区域大小以及积木的数量。
  接下来M行,每行包含两个整数R和C(1<=R,C<=N),表示每个积木放置的位置。

Output

  输出最少操作次数。输入保证有解。
 

分析

可以把这题变成用一个面积m的矩形,最多可以覆盖多少个有积木的区域。(why?自行脑补,可画图)。
然后就简单了,先预处理出从1,1到i,j这个矩形中有多少个区域有积木,记在s[i,j]。
枚举面积为m的矩形的边长,用

f[i,j]=s[i,j]s[im1,j]s[i,jn1]+s[im1,jn1]

计算,其中f[i,j]表示用i,j为右下角的矩形中的有积木的区域个数。
m1,n1为矩形面积。
答案为总个数—可以覆盖最多个有积木的区域。

代码

var
  i,j,k:longint;
  f:array[0..200,0..200] of longint;
  a:array[0..200,0..200] of longint;
  b:array[0..300] of longint;
  n1,m1:longint;
  n,m:longint;
  ans,max:longint;

begin
  readln(n,m);
  for i:=1 to m do
    begin
      readln(j,k);
      f[j,k]:=1;
    end;
  for i:=1 to n do
    for j:=1 to n do
      f[i,j]:=f[i-1,j]+f[i,j-1]-f[i-1,j-1]+f[i,j];
  b[0]:=0;
  for i:=1 to m do
    begin
      if m mod i=0
        then
          begin
            b[0]:=b[0]+1;
            b[b[0]]:=i;
          end;
    end;
  for i:=1 to b[0] do
    begin
      n1:=b[i];
      m1:=m div b[i];
      if (n1>n) or (m1>n)
        then continue;
      max:=0;
      for j:=n1 to n do
        for k:=m1 to n do
          begin
            if f[j,k]-f[j-n1,k]-f[j,k-m1]+f[j-n1,k-m1]>max
              then max:=f[j,k]-f[j-n1,k]-f[j,k-m1]+f[j-n1,k-m1];
          end;
      if ans<max then ans:=max;
    end;
  write(m-ans);
end.

posted @ 2016-07-15 16:19  一个响亮的蒟蒻  阅读(154)  评论(0编辑  收藏  举报