回 帖 发 新 帖 刷新版面

主题:进来看看,帮忙解释清楚一点

{说明:}
{动态规划方程:}
{ ans[t,j]= max ( ans[t-1,j+k] )  (其中,k=-2,-1,0,1,2,且相应位置可达)}
program Pizza_For_Free {Time Limit:3000};
{免费馅饼 将允许时间扩大到3000秒,分值限制在longint范围内}
type
  link=^linetype; {指向记录一个时间单位决策数组的指针类型}
  linetype=array [1..99] of shortint; {记录一个时间单位决策的数组}
var
  f1,f2:text; {输入、输出文件变量}
  w,h:integer; {宽度、高度}
  dd:array [0..100] of array [1..99] of longint; {循环使用的数组,用于表示对应时刻、位置的得分值}
  pro:array [0..3100] of link; {记录决策信息的动态数组}
  dt:array [0..1,1..99] of longint; {循环使用的动态规划数组}
  i,j,k,t:integer; {辅助变量}
  bt,bj:integer; {最大状态记录}
  best:longint; {最大值记录}
  maxt:integer; {最大时间}
  ans:array [1..3100] of shortint; {倒推答案时用的暂存区}
  num:integer;
  pp:longint;
  _t,_j,_v:integer; {暂存初始时间、位置、速度}
  _fz:longint; {暂存分值}
  _saved:boolean; {是否暂存标志}

procedure try_reading; {读入原始数据的过程,其中使用了分段读取的方法。读入初始下落时间不大于t的馅饼}
var
  t0,i,j,v:integer; {初始下落时间}
  fz:longint; {分值}
begin
  fillchar(dd[(t+100) mod 101],sizeof(dd[(t+100) mod 101]),0);
  {t及以后时间读入的块,至迟在t+99时间即进入可接收状态,可对t+100(循环观点下)单元清0,以便下次使用}
  if _saved then {如果上次有预存}
  begin
    if _t>t then exit; {如果预存结果仍不被使用到,则返回,否则用预存结果记录新馅饼}
    _saved:=false;
    if (h-1) mod _v=0 then
    begin
      inc(dd[(_t+(h-1) div _v) mod 101,_j],_fz);
      if (_t+(h-1) div _v)>maxt then maxt:=_t+(h-1) div _v;
    end;
  end;
  if eof(f1) then exit; {文件结束就返回}

  while true do {不断读取,直到初始下落时间大于当前处理时间}
  begin
    if eof(f1) then exit;
    readln(f1,t0,j,v,fz);
    if t0>t then
    begin
      _v:=v;
      _t:=t0;
      _j:=j;
      _fz:=fz;
      _saved:=true;
      exit {暂存返回}
    end;
    if (h-1) mod v<>0 then continue; {标记时间-位置与得到的分值}
    inc(dd[(t0+(h-1) div v) mod 101,j],fz);
    if t0+(h-1) div v>maxt then maxt:=t0+(h-1) div v;
  end;
end;



begin {主程序}
  assign(f1,'INPUT.TXT');
  reset(f1);
  assign(f2,'OUTPUT.TXT');
  rewrite(f2); {文件关联、打开}

  readln(f1,w,h); {读入宽、高}
  for i:=0 to 3100 do {动态内存初始化}
  begin
    new(pro[i]);
    fillchar(pro[i]^,sizeof(pro[i]^),0);
  end;
  for i:=0 to 1 do
for j:=1 to 99 do
  dt[i,j]:=-maxlongint-1;
  {赋初值}
  dt[0,(1+w) div 2]:=0; {-maxlongint-1表示该点不可达}
  fillchar(dd,sizeof(dd),0);
  t:=0;
  maxt:=0;
  _saved:=false;
  try_reading;
  best:=0;
  bt:=0;
  bj:=(w+1) div 2;
  best:=dd[0,(w+1) div 2];

  while true do
  begin
    inc(t); {考虑下一个时间}
    try_reading; {读入数据}
    if eof(f1) and (t>maxt) and not _saved then break; {如果没有新的数据,跳出}
    for j:=1 to w do {考虑各个位置}
    begin
      dt[t mod 2,j]:=-maxlongint-1;
      for k:=-2 to 2 do {考虑5种移动方式}
        if (j+k>0) and (j+k<=w) and (dt[1-t mod 2,j+k]>-maxlongint-1) {如果可能}
        and (dt[1-t mod 2,j+k]+dd[t mod 101,j]>dt[t mod 2,j]) then {而且有效}
        begin
          dt[t mod 2,j]:=dt[1-t mod 2,j+k]+dd[t mod 101,j]; {更新当前最优值}
          pro[t]^[j]:=k;
        end;
      if dt[t mod 2,j]>best then {如果到目前最优,更新之}
      begin
        best:=dt[t mod 2,j];
        bt:=t;
        bj:=j;
      end;
    end;
  end;

  writeln(f2,best); {输出最大值}
  num:=0;
  j:=bj;
  for t:=bt downto 1 do {倒推求解}
  begin
    ans[t]:=-pro[t]^[j];
    inc(j,pro[t]^[j]);
  end;
  for t:=1 to bt do
    writeln(f2,ans[t]);
  close(f1);
  close(f2)
end.
[em2][em2][em2]

回复列表 (共1个回复)

沙发

这道DP不难吧……

我来回复

您尚未登录,请登录后再回复。点此登录或注册