入门题目 :bzoj 3112(zjoi 2013 防守战线) 线性规划+网络流
博客1 重点
博客2 重点

题目描述:

战线可以看作一个长度为n 的序列,现在需要在这个序列上建塔来防守敌兵,在序列第i 号位置上建一座塔有Ci 的花费,且一个位置可以建任意多的塔,费用累加计算。有m 个区间[L1, R1], [L2, R2], …, [Lm, Rm],在第i 个区间的范围内要建至少Di 座塔。求最少花费。

https://blog.csdn.net/SmallSXJ/article/details/73292523

#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const double eps=1e-6;
int n,m;
double c[10005],b[1005],cof[1005][10005];
void pivot(int in,int out,double &res){
    b[out]/=cof[out][in];
    for(int i=1;i<=n;i++) if(i!=in) cof[out][i]/=cof[out][in];
    cof[out][in]=1/cof[out][in];
    for(int i=1;i<=m;i++) if(i!=out&&fabs(cof[i][in])>eps){
        for(int j=1;j<=n;j++) if(j!=in) cof[i][j]-=cof[i][in]*cof[out][j];
        b[i]-=cof[i][in]*b[out];
        cof[i][in]=-cof[i][in]*cof[out][in];
    }
    res+=c[in]*b[out];
    for(int i=1;i<=n;i++) if(i!=in) c[i]-=cof[out][i]*c[in];
    c[in]=-c[in]*cof[out][in];
}   
double simplex(){
    double res=0;
    while(1){
        int in,out;
        for(in=1;in<=n;in++) if(c[in]>eps) break;
        if(in==n+1) break;
        double tmp=inf;
        for(int i=1;i<=m;i++) if(cof[i][in]>eps&&b[i]/cof[i][in]<tmp)
            tmp=b[i]/cof[i][in],out=i;
        if(tmp==inf) return inf;
        pivot(in,out,res);
    }
    return res;
}
int main(){
    freopen("data.in","r",stdin);//
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++){
        scanf("%lf",&b[i]);
    }
    for(int i=1;i<=n;i++){
        int l,r;
        scanf("%d%d%lf",&l,&r,&c[i]);
        for(int j=l;j<=r;j++) cof[j][i]=1;
    }
    printf("%d\n",(int)(simplex()+0.5));
    return 0;
}

模板链接:
https://blog.csdn.net/hdu2014/article/details/51124340
https://github.com/sxysxy/math/blob/master/simplex/simplex.c
原理讲解:
https://blog.csdn.net/qq_36558948/article/details/80640768
http://www.cnblogs.com/zzqsblog/p/5457091.html
https://blog.csdn.net/u013632138/article/details/53609635

CCPC-final
http://www.voidcn.com/article/p-enkpvtgs-brm.html
一个比较好用的模板
https://blog.csdn.net/nike0good/article/details/78798436
https://blog.csdn.net/nike0good/article/category/7344434

//输入 标准型 线性规划,输出目标函数最优解
//输入格式:
/*
第一行两个整数n, m,表示n个自变量,m个约束
第二行n个正数,表示目标函数自变量前的系数
接下来m行,每行n+1个整数
前n个正数描述了这个约束的自变量前的系数,最后一个正数描述了这个约束 <=号 右边的数值
例:
输入(讲义里面讲单纯形法时用的例子):
3 3
3 1 2
1 1 3 30
2 2 5 24
4 1 2 36
输出:
28.00000000
*/

#include<bits/stdc++.h>
using namespace std;
const int Maxn=110,Maxm=59;
class Simplex{
    /* 功能: 接受有n个约束,m个基本变量的方程组a[0~n][0~m] a[0][]存放需要最大化的目标函数,a[][0]存放常数 Base[]存放基本变量的id,初始为1~m Rest[]存放松弛变量的id,初始为m+1~m+n 返回此线性规划的最小值ans 要求方案的话,Base[]中的变量值为0,Rest[]中的变量值为相应行的[0] 如果solve 返回1,说明运行正常ans是它的最大值 返回0,说明无可行解 返回-1,说明解没有最大值 测试: m=2,n=3 double a[4][3]={ {0,1,3}, {8,-1,1}, {-3,1,1}, {2,1,-4} }; solve=1,ans=64/3; 注意ac不了可能是eps的问题 */
    public:
        static const double Inf;
        static const double eps;
    int n,m;
    double a[Maxn][Maxm];
    int Base[Maxm],Rest[Maxn];
    double val[Maxm];
    double ans;
    void pt(){
        for(int i=0;i<=n;i++){
            for(int j=0;j<=m;j++)printf("%.2f ",a[i][j]);
            puts("");
        }
    }
    void pivot(int x,int y){//将第x个非基本变量和第y个基本变量调换
        swap(Rest[x],Base[y]);
        double tmp=-1./a[x][y];
        a[x][y]=-1.;
        for(int j=0;j<=m;j++)a[x][j]*=tmp;
        for(int i=0;i<=n;i++){
            if(i==x||fabs(a[i][y])<eps)continue;
            tmp=a[i][y];
            a[i][y]=0;
            for(int j=0;j<=m;j++)a[i][j]+=tmp*a[x][j];
        }
    }
    bool opt(){
        while(1){
            int csi=0;
            for(int i=1;i<=m;i++)if(a[0][i]>eps&&(!csi||Base[i]<Base[csi]))csi=i;
            if(!csi)break;
            int csj=0;
            double cur;
            for(int j=1;j<=n;j++){
                if(a[j][csi]>-eps)continue;
                double tmp=-a[j][0]/a[j][csi];
                if(!csj||tmp+eps<cur||(fabs(tmp-cur)<eps&&Rest[j]<Rest[csj]))csj=j,cur=tmp;
            }
            if(!csj)return 0;
            pivot(csj,csi);
        }
        ans=a[0][0];
        return 1;
    }
    bool init(){
        ans=0;
        for(int i=1;i<=m;i++)Base[i]=i;
        for(int i=1;i<=n;i++)Rest[i]=m+i;
        int cs=1;
        for(int i=2;i<=n;i++)if(a[i][0]<a[cs][0])cs=i;
        if(a[cs][0]>=-eps)return 1;
        static double tmp[Maxm];
        for(int i=0;i<=m;i++)tmp[i]=a[0][i],a[0][i]=0;
        for(int i=1;i<=n;i++)a[i][m+1]=1.;
        a[0][m+1]=-1.;Base[m+1]=m+n+1;
        pivot(cs,++m);
        opt();
        m--;
        if(a[0][0]<-eps)return 0;
        cs=-1;
        for(int i=1;i<=n;i++){
            if(Rest[i]>m+n){
                cs=i;
                break;
            }
        }
        if(cs>=1){
            int nxt=-1;
            m++;
            for(int i=1;i<=m;i++)if(a[cs][i]>eps||a[cs][i]<-eps){nxt=i;break;}
            pivot(cs,nxt);
            m--;
        }
        for(int i=1;i<=m;i++){
            if(Base[i]>m+n){
                swap(Base[i],Base[m+1]);
                for(int j=0;j<=n;j++)a[j][i]=a[j][m+1];
                break;
            }
        }
        for(int i=1;i<=m;i++)a[0][i]=0;a[0][0]=tmp[0];
        for(int i=1;i<=m;i++)if(Base[i]<=m)a[0][i]=tmp[Base[i]];
        for(int i=1;i<=n;i++){
            if(Rest[i]<=m){
                for(int j=0;j<=m;j++)a[0][j]+=tmp[Rest[i]]*a[i][j];
            }
        }
        return 1;
    }
    void getval(){
        for(int i=1;i<=m;i++)val[i]=0;
        for(int i=1;i<=n;i++)if(Rest[i]<=m)val[Rest[i]]=a[i][0];
        //for(int i=1;i<=m;i++)printf("%.2f ",val[i]);puts("");
    }
    int solve(){
        if(!init())return 0;
        if(!opt())return -1;
        getval();
        return 1;
    }
}solver;
const double Simplex:: Inf=1e80;
const double Simplex:: eps=1e-8;
int main(){
    int m,n,type;
    scanf("%d%d%d",&m,&n,&type);
    solver.a[0][0]=0;
    for(int i=1;i<=m;i++)scanf("%lf",&solver.a[0][i]);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m+1;j++){
            if(j==m+1)scanf("%lf",&solver.a[i][0]);
            else {
                scanf("%lf",&solver.a[i][j]);
                solver.a[i][j]=-solver.a[i][j];
            }
        }
    }
    solver.m=m,solver.n=n;
    int rep=solver.solve();
    if(rep==0)puts("Infeasible");
    else if(rep==-1)puts("Unbounded");
    else {
        printf("%.12f\n",solver.ans);
        if(type==1){
            for(int i=1;i<=m;i++)printf("%.12f%c",solver.val[i],i==m?'\n':' ');
        }
    }
}

再补充一个线性规划问题的描述:

本题中你需要求解一个标准型线性规划:

有 nn 个实数变量 x1,x2,…,xnx1,x2,…,xn 和 mm 条约束,其中第 ii 条约束形如 ∑nj=1aijxj≤bi∑j=1naijxj≤bi。

此外这 nn 个变量需要满足非负性限制,即 xj≥0xj≥0。

在满足上述所有条件的情况下,你需要指定每个变量 xjxj 的取值,使得目标函数 F=∑nj=1cjxjF=∑j=1ncjxj 的值最大。