题目链接

线性规划

  用\(A_{ij}=0/1\)表示第\(i\)天\(j\)类志愿者能否被招募,\(x_i\)为\(i\)类志愿者招募了多少人,\(need_i\)表示第\(i\)天需要多少人,\(C_i\)表示\(i\)类招募志愿者的花费。

  那么我们需要$$最小化\ Cx\s.t.\ Ax\geq need\x\geq 0$$

  (s.t.:subject to,使得满足)

  这是一个最小化线性规划,而不是标准型的最大化线性规划。根据对偶原理(见这儿),我们把它变成:$$最大化\ x*need\s.t.\ xA\leq C\x\geq 0$$

  用非矩阵形式直观地写:$$最小化\ \sum_{i=1}mC_ix_i\s.t. \sum_{i=1}nA_{ij}x_j\geq need_i\ ,\ j=1,2,\ldots,m\x_j\geq 0$$

  利用对偶原理,转化为:$$最大化\ \sum_{i=1}nneed_ix_i\s.t. \sum_{i=1}nA_{ij}x_i\leq C_j\ ,\ j=1,2,\ldots,m\x_i\geq 0$$

  这样就可以直接用单纯形做了。因为\(C_i\)非负,所以一定有解,不需要Init()。

  还有一个问题,线性规划的解是否可能非整数?

  我不知道为什么有这么个...常识定理?

线性规划的问题的最优解为整数的一个必要条件是它的任意一个子方阵的行列式为\(-1, 0, 1\)。

  反正这有\(Candy?\)的结论,我就记住吧。。

  下面有洛谷上题解的证明,证明本题方阵的任意一个子方阵的行列式为\(-1, 0或1\)。(全单位模矩阵

  另外加强版,单纯形应该不对,然而数据比较水。



Proof:


//79668kb	1172ms(果然还是比费用流慢多了)
#include <cmath>
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define eps 1e-8
const int N=1005,M=10005; int n,m;
double A[M][N];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void Pivot(int r,int c)
{
double t=A[r][c]; A[r][c]=1;
for(int i=0; i<=n; ++i) A[r][i]/=t;
for(int i=0; i<=m; ++i)
if(i!=r && fabs(A[i][c])>eps)
{
double t=A[i][c]; A[i][c]=0;
for(int j=0; j<=n; ++j) A[i][j]-=t*A[r][j];
}
}
void Simplex()
{
for(int r,c; ; )
{
r=c=0;
for(int i=1; i<=n; ++i)
if(A[0][i]>eps) {c=i; break;}
if(!c) break;
double mn=1e15;
for(int i=1; i<=m; ++i)
if(A[i][c]>eps && mn>A[i][0]/A[i][c]) r=i, mn=A[i][0]/A[i][c];
if(!r) break;
Pivot(r,c);
}
} int main()
{
n=read(), m=read();
for(int i=1; i<=n; ++i) A[0][i]=read();
for(int i=1,l,r; i<=m; ++i)
{
l=read(), r=read(), A[i][0]=read();
for(int j=l; j<=r; ++j) A[i][j]=1;
}
Simplex(), printf("%.0lf\n",-A[0][0]); return 0;
}

费用流

  用\(u\rightarrow v\ (f,\ c)\)表示一条\(u\rightarrow v\)容量为\(f\),花费为\(c\)的边。

  对于每一类志愿者,连边\(l_i\rightarrow r_i+1\ (INF,\ cost_i)\);

  每相邻的两天,连边\(i\rightarrow i+1\ (INF-need_i,\ 0)\);

  对于源点汇点,连边\(S\rightarrow 1\ (INF,\ 0)\)、\(n+1\rightarrow T\ (INF,\ 0)\)。

  因为一定存在可行解,所以最后流量一定可以扩充成INF。

  对于每两天之间的连边会优先流,因为花费为0,而不经过这条边但覆盖这一段的边的流量之和一定不小于\(need_i\)。即缺少的流量会通过带权边补成INF,且能保证方案最优。

  嗯...好吧我不会写费用流了。。


//1592kb	164ms
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1007,M=11007<<1,INF=0x3f3f3f3f; int src,des,n,m,Enum,H[N],nxt[M],fr[M],to[M],cap[M],cost[M],pre[N],dis[N];
char IN[MAXIN],*SS=IN,*TT=IN; inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AddEdge(int u,int v,int w,int c)
{
fr[++Enum]=u, to[Enum]=v, nxt[Enum]=H[u], H[u]=Enum, cap[Enum]=w, cost[Enum]=c;
fr[++Enum]=v, to[Enum]=u, nxt[Enum]=H[v], H[v]=Enum, cap[Enum]=0, cost[Enum]=-c;
}
bool SPFA()
{
static std::queue<int> q;
static bool inq[N];
memset(dis,0x3f,sizeof dis);
dis[src]=0, q.push(src);
while(!q.empty())
{
int x=q.front(); q.pop();
inq[x]=0;
for(int v,i=H[x]; i; i=nxt[i])
if(cap[i] && dis[v=to[i]]>dis[x]+cost[i])
{
dis[v]=dis[x]+cost[i], pre[v]=i;
if(!inq[v]) inq[v]=1, q.push(v);
}
}
return dis[des]<INF;
}
int MCMF()
{
int res=0, mn=INF;
for(int i=des; i!=src; i=fr[pre[i]])
mn=std::min(mn,cap[pre[i]]);
for(int i=des,v=pre[i]; i!=src; i=fr[v],v=pre[i])
res+=mn*cost[v], cap[v]-=mn, cap[v^1]+=mn;
return res;
} int main()
{
n=read(), m=read(), Enum=1, src=1, des=n+2;
for(int i=1; i<=n; ++i) AddEdge(i,i+1,INF-read(),0);
for(int i=1,l,r; i<=m; ++i) l=read(),r=read(),AddEdge(l,r+1,INF,read());
AddEdge(n+1,des,INF,0);
int res=0;
while(SPFA()) res+=MCMF();
printf("%d\n",res); return 0;
}

BZOJ.1061.[NOI2008]志愿者招募(线性规划 对偶原理 单纯形 / 费用流SPFA)的更多相关文章

  1. BZOJ 1061: [Noi2008]志愿者招募【单纯形裸题】

    1061: [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 4813  Solved: 2877[Submit][Stat ...

  2. BZOJ 1061: [Noi2008]志愿者招募 [单纯形法]【学习笔记】

    1061: [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3975  Solved: 2421[Submit][Stat ...

  3. BZOJ 1061: [Noi2008]志愿者招募 [单纯形法]【学习笔记看另一篇吧】

    1061: [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 3975  Solved: 2421[Submit][Stat ...

  4. BZOJ 1061: [Noi2008]志愿者招募

    1061: [Noi2008]志愿者招募 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 4064  Solved: 2476[Submit][Stat ...

  5. BZOJ 1061: [Noi2008]志愿者招募 费用流

    1061: [Noi2008]志愿者招募 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=1061 Description 申奥成功后,布布 ...

  6. 【刷题】BZOJ 1061 [Noi2008]志愿者招募

    Description 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能完 ...

  7. BZOJ 1061: [Noi2008]志愿者招募(线性规划与网络流)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1061 题意: 思路: 直接放上大神的建模过程!!!(https://www.byvoid.com/z ...

  8. BZOJ 1061 [Noi2008]志愿者招募(费用流)

    题目描述 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能完成,其中第i ...

  9. bzoj 1061 [Noi2008]志愿者招募(数学模型,MCMF)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=1061 [题意] 雇人满足每天至少需要的人数. [思路一] Byvoid的题解 clic ...

随机推荐

  1. Hadoop生态圈-Flume的组件之自定义拦截器(interceptor)

    Hadoop生态圈-Flume的组件之自定义拦截器(interceptor) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客只是举例了一个自定义拦截器的方法,测试字节传输速 ...

  2. SQL记录-PLSQL记录

    PL/SQL记录   PL/SQL记录就是可以容纳不同类型的数据项的数据结构.记录由不同字段,类似于数据库表的行. 例如,要保留跟踪图书馆中的书籍.可能要跟踪有关每本书下面的属性类似:标题,作者,主题 ...

  3. node.js+express,实现RESTful API

    node代码如下(exptest.js): var express = require('express'); var bodyParser = require('body-parser'); var ...

  4. Spring Boot 源码分析 数据源 + Mybatis 配置

    公司今年开始使用 Spring Boot 开发,当然使用 Spring Boot 也是大势所趋,尤其是现在微服务的趋向,当然是选择基于Spring Boot 的 Spring Cloud.(所谓的 S ...

  5. bzoj千题计划256:bzoj2194: 快速傅立叶之二

    http://www.lydsy.com/JudgeOnline/problem.php?id=2194 相乘两项的下标 的 差相同 那么把某一个反过来就是卷积形式 fft优化 #include< ...

  6. Python配置tab自动补全功能

    # cat tab.py #!/usr/bin/python # python tab file import sys import readline import rlcompleter impor ...

  7. Java获取时间,将当前时间减一年,减一天,减一个月

    在Java中操作时间的时候,需要计算某段时间开始到结束的区间日期,常用的时间工具 Date date = new Date();//获取当前时间 Calendar calendar = Calenda ...

  8. 【GDOI2018】所有题目和解题报告

    使用说明:题意和数据范围都只是回忆内容,仅供参考.题解陆续补上. Day 1 第一题 题意:给定n个数字,要求划分成k的连续段使得每个连续段内的数字之和相同,求最大的k.n,Σai<=10^6. ...

  9. 20155212 2016-2017-2 《Java程序设计》第8周学习总结

    20155212 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 Chapter14 1. Channel架构与操作 想要取得Channel的实作对象,可以使 ...

  10. Spark笔记之Catalog

    一.什么是Catalog Spark SQL提供了执行sql语句的支持,sql语句是以表的方式组织使用数据的,而表本身是如何组织存储的呢,肯定是存在一些元数据之类的东西了,Catalog就是Spark ...