TYVJ1191(迎春舞会之三人组舞)

算法:DP
看起来短短的不到50行的代码,但是从构建DP方程来说,本题确实属于难题。
DP方程:f[i,j]:=min(f[i,j],min(f[i-1,j],f[i-2,j-1]+sqr(a[i-1]-a[i])));

思路是只分站在两边的人,而站在中间的人不参加计算,同时要选最小的一定是选邻近的,因为邻近的差值最小。

program P1191;

const
  maxn=5000;
  maxm=1000;

var
  a:array [0..maxn] of longint;
  f:array [0..maxn,0..maxm] of longint;{f[i,j]表示前i个人分成j组的最小残废程度。目标就是f[n,m]。}
  m,n:longint;
  
procedure init;
var
  i:longint;
begin
  readln(m,n);
  for i:=n downto 1 do read(a[i]);{倒着记录,即a[1]最大,a[n]最小。}
  fillchar(f,sizeof(f),100);{求最小,初始化成最大。}
  for i:=1 to n do f[i,0]:=0;{前i个数分成0组的最小残废程度肯定是0。}
  f[3,1]:=sqr(a[3]-a[2]);{这个手工计算一下,前3个数分成1组。}
end;

function min(x,y:longint):longint;
begin
  if x>y then exit(y) else exit(x);
end;

procedure main;
var
  i,j:longint;
begin
  for i:=4 to n do{3的算过了,从4开始算。}
    begin
      for j:=1 to m do
        begin
          if i>=3*j then{限制条件,即人数必须大于等于当前要分的组数中的人数。}
            begin
              f[i,j]:=min(f[i,j],min(f[i-1,j],f[i-2,j-1]+sqr(a[i]-a[i-1])));
            end;
        end;
    end;
end;

begin
  assign(input,'P1191.in'); reset(input);
  assign(output,'P1191.out'); rewrite(output);

  init;
  main;
  writeln(f[n,m]);
  
  close(input); close(output);
end.


你可能感兴趣的:(output,input,算法)