【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.
null