题目大意:给定一个长度为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; }
原文地址:http://blog.csdn.net/popoqqq/article/details/44727123