【bzoj1061】[Noi2008]志愿者招募

本文介绍了使用单纯形法和费用流解决线性规划问题的方法。通过将线性规划问题转化为费用流问题,并利用最小费用最大流算法求解。同时讨论了单纯形法的基本原理及其在实际编程中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

= =跟上一道基本相同,可以单纯形法解线性规划,也可以费用流.
写费用流的话建图就是一般的线性规划转费用流的套路,加上基变量,然后化成等式,每个下式减上式之后可以化成表示流量平衡的等式,然后根据等式建图就好了,跑一个最小费用最大流.
写单纯形没有写网络流好理解,单纯形的话因为这是最小化费用的,首先要转化成对偶问题(我到现在也不能理解对偶问题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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值