bzoj3550【ONTAK2010】Vacation

3550: [ONTAK2010]Vacation

Time Limit: 10 Sec   Memory Limit: 96 MB
Submit: 161   Solved: 120
[ Submit][ Status][ Discuss]

Description

有3N个数,你需要选出一些数,首先保证任意长度为N的区间中选出的数的个数<=K个,其次要保证选出的数的个数最大。

Input

第一行两个整数N,K。
第二行有3N个整数。

Output


一行一个整数表示答案。

Sample Input

5 3
14 21 9 30 11 8 1 20 29 23 17 27 7 8 35

Sample Output

195

HINT

【数据范围】

N<=200,K<=10。

Source

By Sbullet




费用流+线性规划

这道题和bzoj1061志愿者招募的做法很类似。先列出流量的平衡方程(小于等于可以用加入辅助变量解决),再通过差分建立2n+2个等式。将这2n+2个等式看作点,根据流量平衡方程来连边,最后跑最大费用最大流。




#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<queue>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define maxn 1000
#define maxm 20000
#define ll long long
#define pa pair<int,int>
#define inf 1000000000
using namespace std;
struct edge_type
{
	int from,to,next,v,c;
}e[maxm];
int n,k,s,t,ans=0,cnt=1;
int head[maxn],dis[maxn],p[maxn],a[maxn];
bool inq[maxn];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void add_edge(int x,int y,int v,int c)
{
	e[++cnt]=(edge_type){x,y,head[x],v,c};head[x]=cnt;
	e[++cnt]=(edge_type){y,x,head[y],0,-c};head[y]=cnt;
}
inline bool spfa()
{
	queue<int>q;
	memset(inq,false,sizeof(inq));
	F(i,1,t) dis[i]=inf;
	dis[s]=0;inq[s]=true;q.push(s);
	while (!q.empty())
	{
		int x=q.front();inq[x]=false;q.pop();
		for(int i=head[x];i;i=e[i].next)
		{
			int y=e[i].to;
			if (e[i].v&&dis[y]>dis[x]+e[i].c)
			{
				dis[y]=dis[x]+e[i].c;
				p[y]=i;
				if (!inq[y]){inq[y]=true;q.push(y);}
			}
		}
	}
	return dis[t]!=inf;
}
inline void mcf()
{
	while (spfa())
	{
		int tmp=inf;
		for(int i=p[t];i;i=p[e[i].from]) tmp=min(tmp,e[i].v);
		ans+=dis[t]*tmp;
		for(int i=p[t];i;i=p[e[i].from]){e[i].v-=tmp;e[i^1].v+=tmp;}
	}
}
int main()
{
	n=read();k=read();
	s=2*n+3;t=s+1;
	F(i,1,3*n) a[i]=read();
	F(i,1,n)
	{
		add_edge(1,i+1,1,-a[i]);
		add_edge(i+1,i+n+1,1,-a[n+i]);
		add_edge(i+n+1,2*n+2,1,-a[2*n+i]);
	}
	F(i,1,2*n+1) add_edge(i,i+1,inf,0);
	add_edge(s,1,k,0);
	add_edge(2*n+2,t,k,0);
	mcf();
	printf("%d\n",-ans);
}


你可能感兴趣的:(网络流,线性规划,bzoj)