BZOJ_3550_[ONTAK2010]Vacation&&BZOJ_1283:_序列_网络流解线性规划

BZOJ_3550_[ONTAK2010]Vacation&&BZOJ_1283:_序列_网络流解线性规划

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


 

设xi为第i个数是否选。

于是我们有n-m+1个方程

$\begin{matrix}
xi\ge 0\\
x1+x2+x3+x4+x5\le K\\
x2+x3+x4+x5+x6\le K\\
x3+x4+x5+x6+x7\le K\\
x4+x5+x6+x7+x8\le K\\
x5+x6+x7+x8+x9\le K\\
x6+x7+x8+x9+x10\le K\\
\end{matrix}$

变成线性等式

$\begin{matrix}
xi\ge 0\\
yi\ge 0\\
x1+x2+x3+x4+x5+y1=K\\
x2+x3+x4+x5+x6+y2=K\\
x3+x4+x5+x6+x7+y3=K\\
x4+x5+x6+x7+x8+y4=K\\
x5+x6+x7+x8+x9+y5=K\\
x6+x7+x8+x9+x10+y6=K\\
\end{matrix}$

差分一下增加一个方程

$\begin{matrix}
xi\ge 0\\
yi\ge 0\\
x1+x2+x3+x4+x5+y1-K=0\\
x6-x1+y2-y1=0\\
x7-x2+y3-y2=0\\
x8-x3+y4-y3=0\\
x9-x4+y5-y4=0\\
x10-x5+y6-y5=0\\
-x6-x7-x8-x9-x10-y6+K=0\\
\end{matrix}$

然后建图跑最大费用最大流。

对于方程,建立n-m+1个点,对于变量x,找到系数为+1的方程位置和系数为-1的方程位置连边(inf,a[i])。

对于y变量连i->i+1(inf,0)。S->1(K,0),n-m+2->T(K,0)。

 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1050
#define M 100050
#define S (n-m+3)
#define T (n-m+4)
#define inf (1<<30)
int head[N],to[M],nxt[M],cnt=1,path[N],dis[N],Q[N],l,r,inq[N],flow[M],val[M];
int n,m,K,a[N];
inline void add(int u,int v,int f,int w) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f; val[cnt]=w;
    to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0; val[cnt]=-w;
}
bool spfa() {
    memset(dis,0x80,sizeof(dis));
    memset(path,0,sizeof(path));
    l=r=0; Q[r++]=S; dis[S]=0; inq[S]=1;
    while(l!=r) {
        int x=Q[l++],i; if(l==T+1) l=0; inq[x]=0;
        for(i=head[x];i;i=nxt[i]) {
            if(flow[i]&&dis[to[i]]<dis[x]+val[i]) {
                dis[to[i]]=dis[x]+val[i];
                path[to[i]]=i^1; 
                if(!inq[to[i]]) {
                    inq[to[i]]=1; Q[r++]=to[i]; if(r==T+1) r=0;
                }
            }
        }
    }
    return path[T];
}
void mcmf() {
    int minc=0,maxf=0,i;
    while(spfa()) {
        int nf=1<<30;
        for(i=T;i!=S;i=to[path[i]]) {
            nf=min(nf,flow[path[i]^1]);
        }
        for(i=T;i!=S;i=to[path[i]]) {
            flow[path[i]]+=nf; 
            flow[path[i]^1]-=nf;
            minc+=nf*val[path[i]^1];
        }
        maxf+=nf;
    }
    printf("%d\n",minc);
}
int main() {
    scanf("%d%d%d",&n,&m,&K);
    int i;
    for(i=1;i<=n;i++) {
        scanf("%d",&a[i]);
    }
    add(S,1,K,0); add(n-m+2,T,K,0);
    for(i=1;i<=n-m+1;i++) add(i,i+1,inf,0);
    for(i=1;i<=n;i++) {
        if(i<=m) add(1,i+1,1,a[i]);
        else if(i>n-m) add(i-m+1,n-m+2,1,a[i]);
        else add(i-m+1,i+1,1,a[i]);
    }
    mcmf();
}

 

posted @ 2018-05-24 07:22  fcwww  阅读(172)  评论(0编辑  收藏  举报