zoukankan      html  css  js  c++  java
  • bzoj 4842 [Neerc2016]Delight for a Cat 最小费用最大流,线性规划

    题意:有n个小时,对于第i个小时,睡觉的愉悦值为si,打隔膜的愉悦值为ei,同时对于任意一段连续的k小时,必须至少有t1时间在睡觉,t2时间在打隔膜。如果要获得的愉悦值尽
    量大,求最大的愉悦值和睡觉还是打隔膜的方案。(输出两行,第一行为最大愉悦值,第二行n个字符第i个字符为S则表示第i个小时在睡觉,为E则表示第i个小时在打隔膜)
    我现在还没学线性规划的一系列东西(真丢人),写一下直观上的理解,学完线性规划和差分建图再回来写题解。
    直观理解

    首先当睡觉或者打隔膜任意一个活动满足其时间条件时,另一个也一定满足时间条件。

    1.先考虑打隔膜的时间必须为t2时怎么解决。

    设起初所有时间都在睡觉,那么我们需要这个睡觉的权值和-最小的sigma( si-ei )。

    对每第i个点向第i+k个点引一条边,不存在则引向结尾的点,流量为1,消费为si-ei。(这条边表示第 i 小时选择了打隔膜)

    虚点引到[ 1 , k ]点各一条边,流量无限,消费为0。 起始点引向虚点一条边,流量为t2。

    这样建图保证了第i个点和第i+k个点一定一起取,从而保证了每个区间最后都一定有t2个时间在打隔膜(可以证明 : 必须有t2个时间打隔膜时,一定有i和i+k一起取)。

    2.现在考虑可以随意使用的k-t1-t2个时间。

    对第i个点向第i+1个点引一条边,流量为k-t1-t2,消费为0。此时起始点向虚点的边流量应变为k-t1。

    显然有t2条路的选择和1中的没有什么分别。但i到i+1的路和起始点更多的流量给选择更多的打隔膜边留下了机会,我们还可以在每个k区间多选k-t1-t2条打隔膜边。

    现在符合题意了

    然后跑费用流。emm算是需要记忆的经典模型(其实只是我自己写不出来)?

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #include<cmath>
     6 #include<queue>
     7 using namespace std;
     8 #define LL long long
     9 const int maxn=11000;
    10 const int minf=1000000;
    11 int n,k,t1,t2;
    12 int SS,S,T;
    13 LL a[maxn]={},b[maxn]={};
    14 struct nod{
    15     int x,y,v,next,rev;LL co;
    16 }e[maxn*10];
    17 int head[maxn]={},tot=0;
    18 LL dis[maxn]={}; int fa[maxn]={};bool vis[maxn]={};
    19 void init(int x,int y,int v,LL co){
    20     e[++tot].x=x;e[tot].y=y;e[tot].v=v;e[tot].co=co;
    21     e[tot].next=head[x];head[x]=tot;e[tot].rev=tot+1;
    22     
    23     e[++tot].x=y;e[tot].y=x;e[tot].v=0;e[tot].co=-co;
    24     e[tot].next=head[y];head[y]=tot;e[tot].rev=tot-1;
    25 }
    26 queue<int>q;
    27 bool SPFA(){
    28     memset(vis,0,sizeof(vis));
    29     memset(fa,0,sizeof(fa));
    30     memset(dis,31,sizeof(dis));
    31     //cout<<dis[1]<<endl;
    32     q.push(S);vis[S]=1;dis[S]=0;
    33     while(!q.empty()){
    34         int x=q.front();q.pop();vis[x]=0;
    35         for(int i=head[x];i;i=e[i].next){
    36             if(e[i].v){
    37                 if(dis[e[i].y]>dis[x]+e[i].co){
    38                     dis[e[i].y]=dis[x]+e[i].co;
    39                     fa[e[i].y]=i;
    40                     if(!vis[e[i].y]){
    41                         vis[e[i].y]=1;
    42                         q.push(e[i].y);
    43                     }
    44                 }
    45             }
    46         }
    47     }
    48     return fa[T];
    49 }
    50 LL fyl(){
    51     int val=minf;LL ans=0;
    52     for(int i=fa[T];i;i=fa[e[i].x])val=min(val,e[i].v);
    53     for(int i=fa[T];i;i=fa[e[i].x]){
    54         ans+=e[i].co;e[i].v-=val;e[e[i].rev].v+=val;
    55     }
    56     return ans;
    57 }
    58 int main(){
    59     scanf("%d%d%d%d",&n,&k,&t1,&t2);
    60     SS=n+1;S=SS+1;T=S+1;
    61     for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    62     for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
    63     for(int i=1;i<=n;i++)init(i,i+k>n?T:i+k,1,a[i]-b[i]);
    64     for(int i=1;i<=n;i++)init(i,i+1>n?T:i+1,k-t1-t2,0);
    65     for(int i=1;i<=k;i++)init(SS,i,minf,0);
    66     init(S,SS,k-t1,0);
    67     LL ans=0;
    68     for(int i=1;i<=n;i++)ans+=a[i];
    69     while(SPFA())ans-=fyl();
    70     printf("%lld
    ",ans);
    71     for(int i=1;i<2*n;i+=2){
    72         if(!e[i].v)printf("E");
    73         else printf("S");
    74     }printf("
    ");
    75     return 0;
    76 }
    View Code

  • 相关阅读:
    UILabel 详解
    didMoveToSuperView 引发的思考
    Source
    设计模式
    Code ReView
    UIApearance
    UINavigationBar
    initWithNibName与viewDidLoad的执行关系以及顺序
    bLock 回调 就是这么简单!
    程序语言小记
  • 原文地址:https://www.cnblogs.com/137shoebills/p/8871648.html
Copyright © 2011-2022 走看看