zoukankan      html  css  js  c++  java
  • luogu P3980 [NOI2008]志愿者招募

    传送门

    网络流又一神仙套路应用

    首先考虑列不等式,设(x_i)为第i种人的个数,记(b_{i,j})为第i种人第j天是否能工作,那么可以列出n个不等式,第j个为(sum_{i=1}^{m}b_{i,j}x_ige a_j)

    然后将这些不等式转成等式,新开变量y,则那些不等式可以写为$$egin{cases}b_{1,1}x_1+b_{2,1}x_2...+b_{m,1}x_m=a_1+y_1_{1,2}x_1+b_{2,2}x_2...+b_{m,2}x_m=a_2+y_2......end{cases}$$

    然后每个式子都减去上面的式子(假装最后有一个(0=0)的式子),然后得到(n+1)个等式.每个等式再移项,使得系数全为正数.我们发现每个变量分别在某个等式左边出现一次,也在某个右边出现一次.所以可以联系网络流是流入流量=流出流量的,这里把每个等式看做一个点,左边看做流入,右边看做流出.对于变量(x_i),从流出的点向流入的点连流量为能用的最大次数(本题为Inf),费用为单个代价的边;对于变量(y_i),从流出的点向流入的点连流量为能用的最大次数(本题为Inf),费用为0的边;对于常数项(a_i),从原点向流入点连流量(a_i)费用0边,从流出点向汇点连流量(a_i)费用0边,然后费用流求费用就好了

    感性理解一下?(

    #include<bits/stdc++.h>
    #define LL long long
    #define il inline
    #define re register
    #define db double
    
    using namespace std;
    const int N=1e4+10,M=1e5+10;
    il int rd()
    {
        int x=0,w=1;char ch=0;
        while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*w;
    }
    int n,m;
    int a[N],b[N][3];
    int ps,pt,to[M],nt[M],c[M],hd[N],tot=1;
    LL w[M];
    il void add(int x,int y,int z,int zz)
    {
        ++tot,to[tot]=y,nt[tot]=hd[x],c[tot]=z,w[tot]= zz,hd[x]=tot;
        ++tot,to[tot]=x,nt[tot]=hd[y],c[tot]=0,w[tot]=-zz,hd[y]=tot;
    }
    LL di[N],ans;
    int pre[N],fw[N];
    bool v[N];
    queue<int> q;
    il bool csfl()
    {
        memset(di,0x3f3f3f,sizeof(di));
        memset(fw,0,sizeof(fw));
        di[ps]=0,fw[ps]=1<<30,v[ps]=1,q.push(ps);
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(int i=hd[x];i;i=nt[i])
            {
                int y=to[i];
                if(c[i]>0&&di[y]>di[x]+w[i])
                {
                    di[y]=di[x]+w[i];
                    pre[y]=i,fw[y]=min(fw[x],c[i]);
                    if(!v[y]) v[y]=1,q.push(y);
                }
            }
            v[x]=0;
        }
        if(di[pt]==di[pt+1]) return 0;
        ans+=1ll*di[pt]*fw[pt];
        int x=pt;
        while(x^ps)
        {
            int i=pre[x];
            c[i]-=fw[pt],c[i^1]+=fw[pt];
            x=to[i^1];
        }
        return 1;
    }
    
    int main()
    {
        n=rd(),m=rd();
        for(int i=1;i<=n;++i) a[i]=rd();
        for(int i=1;i<=m;++i) b[i][0]=rd(),b[i][1]=rd(),b[i][2]=rd();
        ps=0,pt=n+3;
        for(int i=1;i<=m;++i) add(b[i][1]+1,b[i][0],1<<30,b[i][2]);
        for(int i=1;i<=n;++i) add(i,i+1,1<<30,0);
        for(int i=1;i<=n;++i) add(ps,i+1,a[i],0),add(i,pt,a[i],0);
        while(csfl());
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    springboot + rabbitmq 做智能家居,我也没想到会这么简单
    分享 10个我常逛的国外技术社区,真的受益匪浅!
    被迫重构代码,这次我干掉了 if-else
    过滤器 和 拦截器 6个区别,别再傻傻分不清了
    看了 100多份简历后,想给找工作的程序员几点建议
    不会看 Explain执行计划,劝你简历别写熟悉 SQL优化
    友情链接
    关于我
    10w行级别数据的Excel导入优化记录
    kafka 监控工具 eagle 的安装(内附高速下载地址)
  • 原文地址:https://www.cnblogs.com/smyjr/p/10269427.html
Copyright © 2011-2022 走看看