• 【BZOJ】【3550】【ONTAK2010】Vacation


    网络流/费用流


      Orz太神犇了这题……

      我一开始想成跟Intervals那题一样了……每个数a[i]相当于覆盖了(a[i]-n,a[i]+n)这个区间……但是这样是错的!!随便就找出反例了……我居然还一直当正解……

      实际上刚刚那个思路还有一个问题:题目中的长度为N的区间指的是给的原序列!而不是权值的区间!题就理解错了……

      看了下zyf的题解,才明白过来,要用跟志愿者招募一样的方法来做;另外,志愿者招募时每种志愿者是有无限多名的,但这题中每个数只能选一次,所以边权为a[i]的边的流量不能是INF,而是1。

    题解:
    做这题真是一种折磨。。。
    复习了一下根据流量平衡方程建图的方法,主要是膜拜了byvoid的志愿者招募的题解。。。
    让我们先列出流量平衡方程:a[i]表示i选不选,b[i]表示第i个等式的辅助变量
    则:
    0=0
    a[1]+a[2]+……a[n]+b[1]=k
    a[2]+a[3]+……a[n+1]+b[2]=k
    …………
    a[2*n+1]+a[2*n+2]+……+a[3*n]+b[2*n+1]=k
    0=0
    差分之后是
    a[1]+a[2]+……a[n]+b[1]=k
    a[n+1]-a[1]+b[2]-b[1]=0
    a[n+2]-a[2]+b[3]-b[2]=0
    …………
    -a[2*n+1]-a[2*n+2]-………-a[3*n]-b[2*n+1]=-k
     
    根据BYVOID所说的这段话:
    可以发现,每个等式左边都是几个变量和一个常数相加减,右边都为0,恰好就像网络流中除了源点和汇点的顶点都满足流量平衡。每个正的变量相当于流入该顶点的流量,负的变量相当于流出该顶点的流量,而正常数可以看作来自附加源点的流量,负的常数是流向附加汇点的流量。因此可以据此构造网络,求出从附加源到附加汇的网络最大流,即可满足所有等式。而我们还要求noi_employee_3最小,所以要在X变量相对应的边上加上权值,然后求最小费用最大流
     
    所以我们构图:
    复制代码
        s=0;t=3*n+1;
        for1(i,3*n)a[i]=read();
        insert(s,1,k,0);insert(2*n+2,t,k,0);
        for1(i,n)insert(1,i+1,1,-a[i]);
        for2(i,n+1,2*n)insert(i-n+1,i+1,1,-a[i]);
        for2(i,2*n+1,3*n)insert(i-n+1,2*n+2,1,-a[i]);
        for1(i,2*n+1)insert(i,i+1,inf,0);
    复制代码

    需要搞清楚a[i]在哪个等式中第一次出现,在哪个等式中第二次出现,以及正负号各是什么。

    b[i]的出现很显然,i为正,i+1为负

    然后求最大费用最大流就可以过了。

      1 /**************************************************************
      2     Problem: 3550
      3     User: Tunix
      4     Language: C++
      5     Result: Accepted
      6     Time:20 ms
      7     Memory:6016 kb
      8 ****************************************************************/
      9 
     10 //BZOJ 3550
     11 #include<cmath>
     12 #include<vector>
     13 #include<cstdio>
     14 #include<cstring>
     15 #include<cstdlib>
     16 #include<iostream>
     17 #include<algorithm>
     18 #define rep(i,n) for(int i=0;i<n;++i)
     19 #define F(i,j,n) for(int i=j;i<=n;++i)
     20 #define D(i,j,n) for(int i=j;i>=n;--i)
     21 #define pb push_back
     22 #define CC(a,b) memset(a,b,sizeof(a))
     23 using namespace std;
     24 int getint(){
     25     int v=0,sign=1; char ch=getchar();
     26     while(!isdigit(ch)) {if(ch=='-') sign=-1; ch=getchar();}
     27     while(isdigit(ch))  {v=v*10+ch-'0'; ch=getchar();}
     28     return v*sign;
     29 }
     30 typedef long long LL;
     31 const int N=2000,M=200000,INF=~0u>>2;
     32 const double eps=1e-8;
     33 /*******************template********************/
     34 int n,m,k,a[N],b[N],c[N],w[N];
     35 LL ans;
     36 struct edge{int from,to,v,c;};
     37 struct Net{
     38     edge E[M];
     39     int head[N],next[M],cnt;
     40     void ins(int x,int y,int z,int c){
     41         E[++cnt]=(edge){x,y,z,c};
     42         next[cnt]=head[x]; head[x]=cnt;
     43     }
     44     void add(int x,int y,int z,int c){
     45         ins(x,y,z,c); ins(y,x,0,-c);
     46     }
     47     int S,T,d[N],from[N],Q[M];
     48     bool inq[N];
     49     bool spfa(){
     50         int l=0,r=-1;
     51         F(i,0,T)d[i]=INF;
     52         d[S]=0; Q[++r]=S; inq[S]=1;
     53         while(l<=r){
     54             int x=Q[l++]; inq[x]=0;
     55             for(int i=head[x];i;i=next[i])
     56                 if(E[i].v && d[x]+E[i].c<d[E[i].to]){
     57                     d[E[i].to]=d[x]+E[i].c;
     58                     from[E[i].to]=i;
     59                     if(!inq[E[i].to]){
     60                         Q[++r]=E[i].to;
     61                         inq[E[i].to]=1;
     62                     }
     63                 }
     64         }
     65         return d[T]!=INF;
     66     }
     67     void mcf(){
     68         int x=INF;
     69         for(int i=from[T];i;i=from[E[i].from])
     70             x=min(x,E[i].v);
     71         for(int i=from[T];i;i=from[E[i].from]){
     72             E[i].v-=x;
     73             E[i^1].v+=x;
     74         }
     75         ans+=x*d[T];
     76     }
     77     void init(){
     78         m=n=getint(); m*=3; k=getint(); cnt=1;
     79         F(i,1,m) a[i]=getint();
     80         S=0; T=2*n+3;
     81         add(S,1,k,0);
     82         add(n*2+2,T,k,0);
     83         F(i,1,n*2+1) add(i,i+1,INF,0);
     84         
     85         F(i,2,n+1) add(1,i,1,-a[i-1]);
     86         F(i,n+2,2*n+1) add(i,2*n+2,1,-a[i+n-1]);
     87         F(i,2,n+1) add(i,i+n,1,-a[i+n-1]);
     88         
     89         while(spfa()) mcf();
     90         printf("%lld
    ",-ans);
     91     }
     92 }G1;
     93 int main(){
     94 #ifndef ONLINE_JUDGE
     95     freopen("input.txt","r",stdin);
     96 //    freopen("output.txt","w",stdout);
     97 #endif
     98     G1.init();
     99     return 0;
    100 }
    View Code

    3550: [ONTAK2010]Vacation

    Time Limit: 10 Sec  Memory Limit: 96 MB
    Submit: 141  Solved: 105
    [Submit][Status][Discuss]

    Description

    有3N个数,你需要选出一些数,首先保证任意长度为N的区间中选出的数的个数<=K个,其次要保证选出的数的个数最大。

    Input

    第一行两个整数N,K。
    第二行有3N个整数。

    Output

    一行一个整数表示答案。

    Sample Input

    5 3
    14 21 9 30 11 8 1 20 29 23 17 27 7 8 35

    Sample Output

    195

    HINT

    【数据范围】

    N<=200,K<=10。

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    Node.js
    EFCore-Migrations
    C#核心语法
    C#编程总结--总目录
    PHP ServerPush
    汉字转拼音
    用五分钟重温委托,匿名方法,Lambda,泛型委托,表达式树
    Sublime Text 3 绝对神器
    多线程学习总结
    分享: 利用Readability解决网页正文提取问题
  • 原文地址:https://www.cnblogs.com/Tunix/p/4353035.html
Copyright © 2020-2023  润新知