1. 程式人生 > >【bzoj1061】[Noi2008]志願者招募

【bzoj1061】[Noi2008]志願者招募

= =跟上一道基本相同,可以單純形法解線性規劃,也可以費用流.
寫費用流的話建圖就是一般的線性規劃轉費用流的套路,加上基變數,然後化成等式,每個下式減上式之後可以化成表示流量平衡的等式,然後根據等式建圖就好了,跑一個最小費用最大流.
寫單純形沒有寫網路流好理解,單純形的話因為這是最小化費用的,首先要轉化成對偶問題(我到現在也不能理解對偶問題QAQ),我的理解就是把原本的B[i]寫成c[i],c[i]寫成B[i],n寫成m,m寫成n,然後xjb搞一搞就好了,而且本來也感覺單純形這個模板憑理解很難打= =,其實背的話更難,因為背模板其實都是建立在理解的基礎之上的,其實就是寫的熟練罷了,不理解的話真的特別容易寫錯,跟自適應辛普森積分一樣(捂臉),mdzz好的我承認我是數學不好.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>

using namespace std;
const int N=1e3+5,M=1e4+5;
const double eps=1e-7,inf=1e10;

double ans,A[M][N],B[M],c[N];
int n,m,L,R;

inline void pivot(int l,int e)
{
    B[l]/=A[l][e];
    for
(int i=1;i<=n;++i) if (i!=e)A[l][i]/=A[l][e]; A[l][e]=1/A[l][e]; for (int i;i<=m;++i) if (i!=l&&fabs(A[i][e])>eps) { B[i]-=B[l]*A[i][e]; for (int j=1;j<=n;j++) if (j!=e)A[i][j]-=A[i][e]*A[l][j]; A[i][e]=-A[l][e]*A[i][e]; } ans+=c[e]*B[l]; for
(int i=1;i<=n;++i) if (i!=e)c[i]-=c[e]*A[l][i]; c[e]=-c[e]*A[l][e]; } inline void simplex() { int e; while(1) { for (e=1;e<=n;e++) if (c[e]>eps)break; if (e==n+1) break; double t,delta=inf;int l; for (int i=1;i<=m;++i) if (A[i][e]>eps&&(t=B[i]/A[i][e])<delta) l=i,delta=t; pivot(l,e); } } int main() { cin>>n>>m; for (int i=1;i<=n;++i) scanf("%lf",&c[i]); for (int i=1;i<=m;++i) { scanf("%d%d%lf",&L,&R,&B[i]); for (int j=L;j<=R;++j) A[i][j]=1; } simplex(); printf("%.0lf",ans); }