【BZOJ3550】【ONTAK2010】 Vacation 线性规划转费用流

链接:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44750187");
}

题解:

我依然只会做,不会证。

如果初学者,可以一览,想深究,请移步。

After all,i am a Juruo at present.

首先我们可以有基础的线性规划:每连续n点最多选k个。

转换成数学模型:

(其中 a 数组表示选(1)与不选(0),而 t 数组则是辅助变量,将小于等于关系转化为等于关系)

(至于为什么我不用use啊,choose啊什么的作为变量名——你们看一眼它们在公式中变成啥样就知道了——use、choose)

(∑ni=1ai)+t1=k

?

(∑3ni=2n+1ai)+t2n+1=k

然后我们差分一下这2n+1个式子,保留第一个和最后一个式子,会得到:

k=(∑ni=1ai)+t1

a1+t1=an+1+t2

a2+t2=an+2+t3

?

a2n+t2n=a3n+t2n+1

(∑3ni=2n+1ai)+t2n+1=k

然后关键的时刻到了!我们把每个式子看作一个节点,而边则是式子之间的关系。

那么对于此题我们目前就拥有了3n个项为常数的式子节点,和2个项为O(n)的式子节点。(当然还需要两个节点作为超级源和超级汇来控制流量)

点已经明了了,那么边呢?

前面说过边是式子间的关系,而我们不妨把每个等号看作那个节点的本质,那么等号的左边就是节点的入边总容量,而等号的右边就是节点的出边总容量。

然后我们分析每个变量的含义以及定义域,由此来确定每条边(节点之间关系)的费用以及容量。这个应该很显然, a 是取或不取,那么它的容量应该就是简单的 1 费用则是它本身的取值 vali,而 f 是一个辅助变量,显然容量就应该是 inf ,而费用则是 0 。但是因为题目中的限定“k”,所以我们可以将这个容量设为“inf”

图建完了,我们还需要超级源点连源点,容量k,费用0,汇点连超级汇点,容量k,费用0来进行总的限制。

代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 610
#define M 5000
#define inf 0x3f3f3f3f
using namespace std;
struct Eli
{
    int u,v,len,fee,next;
}e[M];
int head[N],cnt;
inline void add(int u,int v,int len,int fee)
{
    e[++cnt].u=u;
    e[cnt].v=v;
    e[cnt].len=len;
    e[cnt].fee=fee;
    e[cnt].next=head[u];
    head[u]=cnt;
}
inline void ADD(int u,int v,int len,int fee)
{add(u,v,len,-fee),add(v,u,0,fee);}
int dist[N],s,t;
int lim[N],pre[N];
bool in[N];
queue<int>q;
void spfa()
{
    while(!q.empty())q.pop();
    memset(dist,0x3f,sizeof dist);

    q.push(s),dist[s]=0,lim[s]=inf;
    int i,u,v;
    while(!q.empty())
    {
        u=q.front(),q.pop(),in[u]=0;
        for(i=head[u];i;i=e[i].next)if(e[i].len)
        {
            if(dist[v=e[i].v]>dist[u]+e[i].fee)
            {
                dist[v]=dist[u]+e[i].fee;
                lim[v]=min(e[i].len,lim[u]);
                pre[v]=i;
                if(!in[v])q.push(v),in[v]=1;
            }
        }
    }
    return ;
}
void handle(int flow)
{
    for(int i=pre[t];i;i=pre[e[i].u])
    {
        e[i].len-=flow;
        e[i^1].len+=flow;
    }
}
int minfee,n,m,p,S,T;
int val[N];
bool build()
{
    int i,j,k;
    int x,y;

    scanf("%d%d",&n,&m);
    S=0,T=n*2+1,cnt=1,s=n*2+2,t=n*2+3;
    ADD(s,S,m,0),ADD(T,t,m,0);

    for(i=1;i<=n*3;i++)scanf("%d",&val[i]);
    for(i=1;i<=n;i++)
    {
        ADD(S,i,1,val[i]);
        ADD(i,i+n,1,val[i+n]);
        ADD(i+n,T,1,val[i+(n<<1)]);
    }
    for(i=1;i<=T;i++)ADD(i-1,i,m,0);
    return 0;
}
int main()
{
    freopen("test.in","r",stdin);
    build();
    while(spfa(),dist[t]<inf)
    {
        minfee+=lim[t]*dist[t];
        handle(lim[t]);
    }
    cout<<(-minfee)<<endl;
    return 0;
}
时间: 2024-11-01 22:41:40

【BZOJ3550】【ONTAK2010】 Vacation 线性规划转费用流的相关文章

【bzoj1283】序列 线性规划与费用流

题目描述 给出一个长度为 的正整数序列Ci,求一个子序列,使得原序列中任意长度为 的子串中被选出的元素不超过K(K,M<=100) 个,并且选出的元素之和最大. 输入 第1行三个数N,m,k. 接下来N行,每行一个字符串表示Ci. 输出 最大和. 样例输入 10 5 3 4 4 4 6 6 6 6 6 4 4 样例输出 30 题解 线性规划与费用流 关于线性规划与费用流的具体讲解参见 bzoj1061 . 这道题和那道差不多,都是给出一大堆限制条件,每个变量在限制条件中的出现是连续的. 所以我们

【bzoj1061】[NOI2008]志愿者招募 线性规划与费用流

题目描述 申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管.布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者.经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人.布布通过了解得知,一共有M 类志愿者可以招募.其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci 元.新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案. 输入

BZOJ3550: [ONTAK2010]Vacation

3550: [ONTAK2010]Vacation Time Limit: 10 Sec  Memory Limit: 96 MBSubmit: 91  Solved: 71[Submit][Status] Description 有3N个数,你需要选出一些数,首先保证任意长度为N的区间中选出的数的个数<=K个,其次要保证选出的数的个数最大. Input 第一行两个整数N,K.第二行有3N个整数. Output 一行一个整数表示答案. Sample Input 5 3 14 21 9 30 11

bzoj3550: [ONTAK2010]Vacation&amp;&amp;1283: 序列

给出一个长度为 的正整数序列Ci,求一个子序列,使得原序列中任意长度为 的子串中被选出的元素不超过K(K,M<=100) 个,并且选出的元素之和最大. 据说是什么经典区间带权限制问题? 有两种写法... 1.可以根据流量平衡列方程,然后添加一个变量将不等式化成等式.具体看NOI2008的志愿者招募. 2.直接每个点依次排开,i->i+1连(k,0)[k是流量限制,0是费用]的边,然后对于一个区间[l,r]就l->r连(1,val):然后源点->1连(k,0),n->T一样,跑

BZOJ 3550 [ONTAK2010]Vacation 线性规划

题意:链接 方法:线性规划 解析: 这是一道蛮简单的单纯性线性规划. 首先我们设Xi表示第i个数是否选择. 则显然 X1+X2+...+Xn<=k X2+X3...+Xn+1<=k - X2n+1+X2n+2+...+X3n<=k 其次0<=Xi<=1 并且我们要最大化∑3ni=1Ci?Xi 观察如上式子,显然为标准型线性规划. 单纯性出解即OK. 代码: #include <cstdio> #include <cstring> #include &l

bzoj3550: [ONTAK2010]Vacation&amp;&amp;bzoj3112: [Zjoi2013]防守战线

学了下单纯形法解线性规划 看起来好像并不是特别难,第二个code有注释.我还有...*=-....这个不是特别懂 第一个是正常的,第二个是解对偶问题的 #include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; const double e

【BZOJ1283/3550】序列/[ONTAK2010]Vacation 最大费用流

[BZOJ1283]序列 Description 给出一个长度为 的正整数序列Ci,求一个子序列,使得原序列中任意长度为 的子串中被选出的元素不超过K(K,M<=100) 个,并且选出的元素之和最大. Input 第1行三个数N,m,k. 接下来N行,每行一个字符串表示Ci. Output 最大和. Sample Input 10 5 3 4 4 4 6 6 6 6 6 4 4 Sample Output 30 HINT 20%的数据:n<=10.100%的数据:N<=1000,k,m&

【BZOJ4842】[Neerc2016]Delight for a Cat 线性规划+费用流

[BZOJ4842][Neerc2016]Delight for a Cat Description ls是一个特别堕落的小朋友,对于n个连续的小时,他将要么睡觉要么打隔膜,一个小时内他不能既睡觉也打隔膜,因此一个小时内他只能选择睡觉或者打隔膜,当然他也必须选择睡觉或打隔膜,对于每一个小时,他选择睡觉或打隔膜的愉悦值是不同的,对于第i个小时,睡觉的愉悦值为si,打隔膜的愉悦值为ei,同时又有一个奥妙重重的规定:对于任意一段连续的k小时,ls必须至少有t1时间在睡觉,t2时间在打隔膜.那么ls想让

线性规划费用流解法(Bzoj1061: [Noi2008]志愿者招募)

题面 传送门 Sol 线性规划费用流解法用与求解未知数为非负数的问题 这道题可以列出一堆形如 \(x[i]+x[j]+x[k]+...>=a[p]\) 的不等式 我们强行给每个式子减去一个东西,使他变成这样 \(x[i]+x[j]+x[k]+...-y[p]==a[p]\) 然后相邻两个式子差分一下 把每个式子看成一个点 那么这样后,在这个题中所有的未知数只会出现在一个方程中 等式左边符号是正的向符号为负的方程连边,费用为代价,如果是补的未知数\(y\),那么费用为零 右边的数是正的连\(s\)