BZOJ1283 序列

来源:互联网 发布:网络运营和网络推广 编辑:程序博客网 时间:2024/05/17 01:17

思路:
这种题目是很经典的模型,相似的还有网络流24题中的最长k可重区间集问题,NOI的志愿者招募等等。一般来说有两种方法:
1.可以根据流量平衡列方程,然后添加一个变量将不等式化成等式。具体看NOI2008的志愿者招募。
2.直接每个点依次排开,i->i+1连(k,0)【k是流量限制,0是费用】的边,然后对于一个区间[l,r]就l->r连(1,val);然后源点->1连(k,0),n->T一样,跑一边最大费用最大流即可。你想 经过每个点的流量都保证了不超过k啊啊。。。。

#include<iostream>#include<cstdio>#include<cstdlib>#include<algorithm>#include<cmath>#include<cstring>#include<string>#include<queue>#include<vector>using namespace std;const int imax=1000+229;const int dmax=imax;const int bmax=200000+229;const int inf=100000229; int n,m,k,S,T;int a[imax];int num,head[dmax],from[bmax],to[bmax],inext[bmax],val[bmax],re[bmax];void iadd(int u,int v,int flow,int nowv){//  printf("%d %d %d %d\n",u,v,flow,nowv);    re[num]=flow; val[num]=nowv;     from[num]=u; to[num]=v; inext[num]=head[u]; head[u]=num++;  }void add(int u,int v,int flow,int nowv) { iadd(u,v,flow,nowv); iadd(v,u,0,-nowv); } void iread(){    S=0;     memset(head,-1,sizeof(head));    scanf("%d%d%d",&n,&m,&k);    T=n+1;    for(int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        add(i-1,i,k,0);        if(i+m<=n) add(i,i+m,1,a[i]);        else add(i,T,1,a[i]);    }    add(n,T,k,0);}int cost[dmax],pre[dmax];bool vis[dmax];queue<int> q; bool spfa(){    for(int i=S;i<=T;i++) cost[i]=-1,pre[i]=-1,vis[i]=0;    cost[S]=1; vis[S]=1; q.push(S);    while(!q.empty())    {        int u=q.front(); q.pop();        vis[u]=false;    //  printf("%d %d-\n",u,cost[u]);        for(int i=head[u];i!=-1;i=inext[i])        {            if(re[i] && cost[to[i]]<cost[u]+val[i])            {                pre[to[i]]=i;                cost[to[i]]=cost[u]+val[i];    //          printf("%d %d %d:%d\n",u,to[i],val[i],cost[to[i]]);                if(!vis[to[i]])                 {    //          printf("%d==\n",to[i],cost[to[i]]);                    q.push(to[i]),vis[to[i]]=1;                }            }           }    }       return cost[T]!=-1;} void iwork(){    int ans=0; int Maxflow=0;    while(spfa())    {        Maxflow=inf;        for(int i=T;i!=S;i=from[pre[i]]) Maxflow=min(Maxflow,re[pre[i]]);        for(int i=T;i!=S;i=from[pre[i]])            {            int now=pre[i];            ans+=val[now]*Maxflow;            re[now]-=Maxflow;            re[now^1]+=Maxflow;        }    }    printf("%d\n",ans);}int main(){    iread();    iwork();    return 0;}
1 0