• 解题报告 比赛


     

    1.        题目

    比赛(Pk.pas/c/cpp

     

    题目描述

         新兵们一般在部队没什么娱乐活动,而且还老有个警官在旁边即即歪歪,所以他们总要找个法子发一下怒气,所以有时候两个不同营的新兵就喜欢一起打架。。。。。。 A营和B营就是典型的例子。而且他们破坏力很大,常常把操场打得这里坑一块那里坑一块,警官很头疼,因为都要他掏腰包。。。。。。

         为了减少损失,他决定每隔一段时间由他自己组织搞次比赛(打架)。

         比赛开始时两个营新兵排成两个队,每个士兵有一个破坏值,然后由警官来安排比赛的人,分任意次来PK,可以是单挑,群挑,或者是单挑群(呵呵,警官只在乎修整费用最少)具体规则如下:

    从后往前,每次从A营选出连续k1(k1>0)个人,从B营选出连续k2(k2>0)个人进行pk。那么这次破坏导致操场的修整费用为 (S1-K1)*(S2-K2)。比赛直到两个队伍都为空时结束。而这次比赛的总修整费用就为每次PK修整费用的和。

    警官拜托你的是使这次比赛的费用最小。

        

    输入数据

        第一行两个正整数L1,L2分别表示两营的人数;

    第二行L1个正整数,描述A 营每个人的破坏值

    第三行L2个正整数,描述B 营每个人的破坏值

         1<=L1,L2<=2000

    输出数据

    一个正整数表示操场的最小修整费用

     

     

    样例输入

    3 2

    1 2 3

    1 2

     

    样例输出

    2

     

    2.        题目实质

    动规求最优解。(废话)

    3.        算法

    地球人都能看出来是动规,问题是,方程怎么写?

    第一种:

    f[i,j] 代表消去序列A1i->l1,序列A2j->l2

    A1[i]+A1[i+1]+……+A1[l1]=Si;A2[j]+A2[j+1]+……+A2[l2]=Tj ;则状态转移方程为: f[i,j]:=min{ f[p,q]+(Si-Sp-p+i)*(Tj-Tq-q+j)  |  (i<p<=l1+1,j<q<=l2+1) }

    初始条件为 f[l1+1,l2+1]=0 ;

    但这样是 O(L^4)

    观察(S1-K1)*(S2-K2)(S1-K1)可以写成[(A1[1]-1)+(A1[2]-1)+……+(A1[K1]-1)],(S2-K2) 类似。

    所以我们可以在读入时就把A1 A2 的所有数全部减 1 ,计算时直接 S1*S2

    假设 S1*S2 S1 A1 序列中两个或两个以上元素的和, S2 类似。那么我们可以把 S1 拆成两个和 S11 S12 ;把 S2 拆成两个和 S21 S22 。则

    S1*S2=(S11+S12)*(S21+S22)=S11*S21+S12*S21+S11*S22+S12*S22>S11*S21+S12*S22 ;

      可见把它们分开消去更优。所以要这样一直拆分下去,直到某个和 S 为一个元素的和。所以每次都在 A1A2 中选择某一序列的一个元素跟另外一个序列的一段(或一个)消去。

    那么状态转移方程就变成了:

           f[i,j]:=min{  f[i+1,q]+A1[i]*(Tj-Tq)  |  (j<q<=l2+1)

                       f[p,j+1]+(Si-Sp)*A2[j]  |  (i<p<=l1+1)  }

     这样为 O(L^3)

    假设A1[i]A2序列的一段 x->(y-1) 一起消去。如下图,

       A1[i]:                    

                          i

       A2[x]->A2[(y-1)]:       ……

                          x    x+1 x+2 ……  y-2 y-1

    这个表示为 f[i,x]=f[i+1y]+A1[i]*(Tx-Ty)

    显然可以看做是 A1[i] A2[x+1]->A2[y-1] 一起消去然后A1[i]再跟A2[x]一起消去,而前者为 f[i,x+1] , 后者为 A1[i]*A2[x]

      所以还可以表示为 f[i,x]=f[i,x+1]+A1[i]*A2[x];

    那么状态转移方程就变成了:

           f[i,j]:=min{ f[i+1,j]+A1[i]*A2[j]         //A1序列的iA2序列从j开始的一段一起消去   

                      f[i,j+1]+A1[i]*A2[j]         //A1序列从i开始的一段与A2序列的j一起消去

                      f[i+1,j+1]+A1[i]*A2[j] }     //A1序列的iA2序列的j一起消去

    这样就是O(L^2)的了。

     

    4.        注意事项

    注意 f 数组的初值!

    5.        程序代码

    SueMiller Pascal

    var l1,l2:integer;

        a1,a2:array[0..2010]of longint;

        i,j:integer;

        f:array[0..2010,0..2010]of longint;

     

    function min(a,b:longint):longint;

    begin

      if a<b then exit(a) else exit(b);

    end;

     

    begin

      assign(input,'Pk.in');reset(input);

      assign(output,'Pk.out');rewrite(output);

     

      readln(l1,l2);

      for i:=1 to l1 do begin read(a1[i]);dec(a1[i]);end;

      for i:=1 to l2 do begin read(a2[i]);dec(a2[i]);end;

     

      filldword(f,sizeof(f)>>2,maxlongint);

      f[l1+1,l2+1]:=0;

      for i:=l1 downto 1 do

        for j:=l2 downto 1 do

          begin

            f[i,j]:=min(min(f[i+1,j],f[i,j+1]),f[i+1,j+1])+a1[i]*a2[j];

          end;

     

      writeln(f[1,1]);

     

      close(input);close(output);

    end.

     

     

  • 相关阅读:
    VS2010 添加项目依赖
    人工鱼群算法 AFSA
    粒子群算法 PSO
    CUDA速度测试
    AGSO 萤火虫算法
    用于WTL工具栏的辅助类CToolBarHelper
    关于结构体内存对齐
    遗传算法 GA
    A*算法
    人工蜂群算法 ABC
  • 原文地址:https://www.cnblogs.com/SueMiller/p/2130915.html
Copyright © 2020-2023  润新知