【BZOJ1061】志愿者招募(单纯形,对偶性)

题意:

这个项目需要N 天才能完成,其中第i 天至少需要
Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用
是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这
并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。
第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负
整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了
方便起见,我们可以认为每类志愿者的数量都是无限多的。
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
思路:线性规划的对偶性 参见《算导》29章

全幺模矩阵可以保证至少有一组整数解

就是a[i,j]取值只为-1,0,1的矩阵

这个线性规划根据对偶性等价于

 1 const eps=1e-8;
 2 var a:array[0..10000,0..1000]of double;
 3     idx,idy,q:array[0..10000]of longint;
 4     b,c:array[0..10000]of double;
 5     n,m,i,j,op,x,y:longint;
 6     mn,p:double;
 7 
 8 procedure swap(var x,y:longint);
 9 var t:longint;
10 begin
11  t:=x; x:=y; y:=t;
12 end;
13 
14 procedure povit(x,y:longint);
15 var i,j,tot:longint;
16     tmp:double;
17 
18 begin
19  swap(idx[y],idy[x]);
20  tmp:=a[x,y]; a[x,y]:=1/a[x,y];
21  for i:=0 to n do
22   if y<>i then a[x,i]:=a[x,i]/tmp;
23  tot:=0;
24  for i:=0 to n do
25   if (i<>y)and((a[x,i]>eps)or(a[x,i]<-eps)) then
26   begin
27    inc(tot); q[tot]:=i;
28   end;
29  for i:=0 to m do
30  begin
31   if (x=i)or((a[i,y]<eps)and(a[i,y]>-eps)) then continue;
32   for j:=1 to tot do a[i,q[j]]:=a[i,q[j]]-a[x,q[j]]*a[i,y];
33   a[i,y]:=-a[i,y]/tmp;
34  end;
35 end;
36 
37 function min(x,y:longint):longint;
38 begin
39  if x<y then exit(x);
40  exit(y);
41 end;
42 
43 begin
44  assign(input,'bzoj1061.in'); reset(input);
45  assign(output,'bzoj1061.out'); rewrite(output);
46  randomize;
47  readln(n,m);
48  for i:=1 to n do read(c[i]);
49  for i:=1 to m do
50  begin
51   readln(x,y,b[i]);
52   for j:=x to y do a[i,j]:=1;
53  end;
54 
55 
56  for i:=1 to n do a[0,i]:=c[i];
57  for i:=1 to m do a[i,0]:=b[i];
58  for i:=1 to n do idx[i]:=i;
59  for i:=1 to m do idy[i]:=i+n;
60  while true do
61  begin
62   x:=0; y:=0;
63   for i:=1 to m do
64    if (a[i,0]<-eps)and((x=0)or(random(2)=1)) then x:=i;
65   if x=0 then break;
66   for i:=1 to n do
67    if (a[x,i]<-eps)and((y=0)or(random(2)=1)) then y:=i;
68   if y=0 then break;
69   povit(x,y);
70  end;
71  while true do
72  begin
73   x:=0; y:=0; mn:=1e15;
74   for i:=1 to n do
75    if a[0,i]>eps then begin y:=i; break; end;
76   if y=0 then break;
77   for i:=1 to m do
78    if (a[i,y]>eps)and(a[i,0]/a[i,y]<mn) then
79    begin
80     mn:=a[i,0]/a[i,y]; x:=i;
81    end;
82   if x=0 then break;
83   povit(x,y);
84  end;
85  writeln(-a[0,0]:0:0);
86  close(input);
87  close(output);
88 end.
原文地址:https://www.cnblogs.com/myx12345/p/6484657.html