解题报告 征兵计划

 

1.        题目 

征兵计划(conscription.pas/c/cpp

题目描述

公元1940622日,德军攻占巴黎,法兰西共和国投降。希特勒为了实现其征服欧洲的野心,准备大举进攻英伦三岛。英国皇家空军紧急启动征兵计划,丘吉尔首相把这项任务交给你负责。

司令部会告诉你每月最少所需新兵的数量。当征召或遣回一个士兵时,会有额外的支出。一旦一个士兵被征召而服役,他将得到政府每月发给的工资。司令部当然会告诉你征召一名士兵的费用,遣回一名士兵的费用和士兵每月工资。现在司令部要求,要把这个征兵计划的费用限制到最低,你每月该征召或遣回多少士兵。

输入数据

    输入文件含有三行。第一行为月数n(不超过12)。第二行含征召一个士兵的费用,一个士兵的工资和遣回一个士兵的费用(≤100)。第三行含n个数,分别表示每月最少需要的士兵人数(≤1000)。每个数据之间有一个空格隔开。

输出数据

    输出仅一行,表示征兵计划的最小总费用。

样例输入

3

4 5 6

10 9 11

样例输出

  199

2.        题目实质 

求满足条件的最小代价。(废话)

3.        算法

动态规划。(但是,一共五个点,贪心过三个,搜索过四个,囧)

因为这个题每一个月的状态都受前面的状态的影响,所以考虑动态规划。

建立一个 f 二维数组,f[I,j] 分别表示第 I 个月有 j 个士兵时,前 I 个月总共花的最少钱数,由此可以得出动态转移方程: f[I,j]:=min(f[I-1,k]+ (j-k)*zheng || (k-j)*qian +j*gongzi).

然后,就是这样。

注意 k j 关系不同时的判断。

边界条件是第一个月的人,另外,这里是正着更新。(背包是倒着更新)

4.        注意事项

注意状态转移时的判断。

如何判断一个题是动态规划:当贪心不太好贪,或是可以举出反例,并且搜索复杂度太高时,写方程的话可以从状态的转移下手,感觉状态太多可以加一个变量。实在不行可以多次动态规划,或是正着跑一遍倒着跑一遍。(暴力 DP

5.        时空复杂度  O(n^3)

6.        程序代码

Leve pascal

var

 f:array[0..12,0..1000] of longint;

 i,j,k,a1,a2,a3,max,ans,n:longint;

 a:array[0..12] of longint;

begin

 assign(input,'conscription.in');

 assign(output,'conscription.out');

 reset(input);

 rewrite(output);

 readln(n);

 readln(a1,a2,a3);

 for i:=1 to n do

 begin

  read(a[i]);

  if a[i]>max then max:=a[i];

 end;

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

 for i:=a[1] to max do

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

 for i:=2 to n do

  for j:=a[i] to max do

   for k:=a[i-1] to max do

    begin

        if k>j then

         begin

          if f[i,j]>f[i-1,k]+a3*(k-j)+j*a2 then

         f[i,j]:=f[i-1,k]+a3*(k-j)+j*a2;

         end

        else

         if f[i,j]>f[i-1,k]+a1*(j-k)+j*a2 then

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

       end;

    ans:=maxlongint;

       for i:=a[n] to max do

       if f[n,i]<ans then ans:=f[n,i];

  writeln(ans);

  close(input);

  close(output);

end.

posted @ 2011-08-06 12:09  木小漾  阅读(299)  评论(0编辑  收藏  举报