天天看點

積木遊戲 紀中 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[i−m1,j]−s[i,j−n1]+s[i−m1,j−n1]

計算,其中f[i,j]表示用i,j為右下角的矩形中的有積木的區域個數。

m1,n1為矩形面積。

答案為總個數—可以覆寫最多個有積木的區域。

代碼

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

begin
  readln(n,m);
  for i:= to m do
    begin
      readln(j,k);
      f[j,k]:=;
    end;
  for i:= to n do
    for j:= to n do
      f[i,j]:=f[i-,j]+f[i,j-]-f[i-,j-]+f[i,j];
  b[]:=;
  for i:= to m do
    begin
      if m mod i=
        then
          begin
            b[]:=b[]+;
            b[b[]]:=i;
          end;
    end;
  for i:= to b[] do
    begin
      n1:=b[i];
      m1:=m div b[i];
      if (n1>n) or (m1>n)
        then continue;
      max:=;
      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.

           

轉載于:https://www.cnblogs.com/a-loud-name/p/6184757.html