BZOJ 1283 序列 费用流

题目大意:给定一个长度为n的序列,要求选一些数,使得任意一个长度为m个区间中最多选k个数,求最大的和

费用流直接跑就是了

把这个序列用流量为k费用为0的边连成一条直线 然后第i个点向第i+m个点连一条费用为a[i]流量为1的边

跑最大费用最大流即可

卡单纯型差评。。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1010
#define S 0
#define T (M-1)
#define INF 0x3f3f3f3f
using namespace std;
int n,m,k,ans;
int a[M];
namespace Max_Cost_Max_Flow{
	struct abcd{
		int to,flow,cost,next;
	}table[1001001];
	int head[M],tot=1;
	void Add(int x,int y,int f,int c)
	{
		table[++tot].to=y;
		table[tot].flow=f;
		table[tot].cost=c;
		table[tot].next=head[x];
		head[x]=tot;
	}
	void Link(int x,int y,int f,int c)
	{
		Add(x,y,f,c);
		Add(y,x,0,-c);
	}
	bool Edmonds_Karp()
	{
		static int q[65540],flow[M],cost[M],from[M];
		static unsigned short r,h;
		static bool v[M];
		int i;
		memset(cost,0xef,sizeof cost);
		q[++r]=S;cost[S]=0;flow[S]=INF;
		while(r!=h)
		{
			int x=q[++h];v[x]=false;
			for(i=head[x];i;i=table[i].next)
				if(table[i].flow&&cost[table[i].to]<cost[x]+table[i].cost)
				{
					cost[table[i].to]=cost[x]+table[i].cost;
					flow[table[i].to]=min(flow[x],table[i].flow);
					from[table[i].to]=i;
					if(!v[table[i].to])
						v[table[i].to]=true,q[++r]=table[i].to;
				}
		}
		if(cost[T]==0xefefefef) return false;
		ans+=flow[T]*cost[T];
		for(i=from[T];i;i=from[table[i^1].to])
			table[i].flow-=flow[T],table[i^1].flow+=flow[T];
		return true;
	}
}
int main()
{
	using namespace Max_Cost_Max_Flow;
	int i;
	cin>>n>>m>>k;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(i=1;i<=n;i++)
	{
		Link(i-1,i,k,0);
		if(i+m<=n)
			Link(i,i+m,1,a[i]);
		else
			Link(i,T,1,a[i]);
	}
	Link(n,T,k,0);
	while( Edmonds_Karp() );
	cout<<ans<<endl;
	return 0;
}


你可能感兴趣的:(费用流,bzoj,BZOJ1283)