BZOJ1283/3550序列/[ONTAK2010]Vacation 最大费用流
Posted CQzhangyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
4 4 4 6 6 6 6 6 4 4
Sample Output
30
HINT
20%的数据:n<=10。
100%的数据:N<=1000,k,m<=100。Ci<=20000。
题解:很难想的费用流建图,看了题解才略懂,下面说一下建图方法和我的理解:
1.S->1...i -> i+1...n->T 容量k,费用0
2.i -> i+m 容量1,费用ai
我的理解是:假如你只有k个流量,要体现出所有的权值,你该如何利用这k个流量?显然你必须重复利用这些流量,就以[l,l+m]和[l+1,l+m+1],l的流量对l+m+1没有影响,所以l+m+1可以直接将l的流量拿过来用,达到节约流量的目的。这样一来,这k个流量在经过每个区间时都会选择权值最大的路径去走,这样跑最大费用流就能得出正确的解。
1283
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; int n,m,k,S,T,cnt,ans; int to[30000],next[30000],head[1010],cost[30000],flow[30000],dis[1010],inq[1010],pe[1010],pv[1010]; queue<int> q; void add(int a,int b,int c,int d) { to[cnt]=b,cost[cnt]=c,flow[cnt]=d,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int bfs() { memset(dis,0x3f,sizeof(dis)); dis[S]=0,q.push(S); int i,u; while(!q.empty()) { u=q.front(),q.pop(),inq[u]=0; for(i=head[u];i!=-1;i=next[i]) { if(dis[to[i]]>dis[u]+cost[i]&&flow[i]) { dis[to[i]]=dis[u]+cost[i],pe[to[i]]=i,pv[to[i]]=u; if(!inq[to[i]]) inq[to[i]]=1,q.push(to[i]); } } } return dis[T]<0x3f3f3f3f; } int main() { scanf("%d%d%d",&n,&m,&k); int i,j,a; S=0,T=n+1; memset(head,-1,sizeof(head)); add(S,1,0,k); for(i=1;i<=n;i++) { add(i,i+1,0,k); scanf("%d",&a); if(i+m<=n) add(i,i+m,-a,1); else add(i,T,-a,1); } while(bfs()) { int mf=1<<30; for(i=T;i!=S;i=pv[i]) mf=min(mf,flow[pe[i]]); ans-=dis[T]*mf; for(i=T;i!=S;i=pv[i]) flow[pe[i]]-=mf,flow[pe[i]^1]+=mf; } printf("%d",ans); return 0; }
3550
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; int n,k,S,T,cnt,ans; int to[30000],next[30000],head[1010],cost[30000],flow[30000],dis[1010],inq[1010],pe[1010],pv[1010]; queue<int> q; void add(int a,int b,int c,int d) { to[cnt]=b,cost[cnt]=c,flow[cnt]=d,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } int bfs() { memset(dis,0x3f,sizeof(dis)); dis[S]=0,q.push(S); int i,u; while(!q.empty()) { u=q.front(),q.pop(),inq[u]=0; for(i=head[u];i!=-1;i=next[i]) { if(dis[to[i]]>dis[u]+cost[i]&&flow[i]) { dis[to[i]]=dis[u]+cost[i],pe[to[i]]=i,pv[to[i]]=u; if(!inq[to[i]]) inq[to[i]]=1,q.push(to[i]); } } } return dis[T]<0x3f3f3f3f; } int main() { scanf("%d%d",&n,&k); int i,j,a; S=0,T=3*n+1; memset(head,-1,sizeof(head)); add(S,1,0,k); for(i=1;i<=3*n;i++) { add(i,i+1,0,k); scanf("%d",&a); if(i+n<=3*n) add(i,i+n,-a,1); else add(i,T,-a,1); } while(bfs()) { int mf=1<<30; for(i=T;i!=S;i=pv[i]) mf=min(mf,flow[pe[i]]); ans-=dis[T]*mf; for(i=T;i!=S;i=pv[i]) flow[pe[i]]-=mf,flow[pe[i]^1]+=mf; } printf("%d",ans); return 0; }
以上是关于BZOJ1283/3550序列/[ONTAK2010]Vacation 最大费用流的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 4278 [ONTAK2015]Tasowanie——后缀数组
BZOJ4275[ONTAK2015]Badania naukowe DP