zoukankan      html  css  js  c++  java
  • bzoj1061: [Noi2008]志愿者招募

    费用流。

    传说中建模之集大成之题。。。

    https://www.byvoid.com/blog/noi-2008-employee 题解

    题解里面关于建模已经讲的很全了。

    我根据自己的理解写写建模的实际意义。

    如果a[i]-a[i-1]>=0,代表需要新雇佣人。否则就代表有人离开了。(离开并不一定要在t[i]+1天,如果后面人多余的话,很早就会离开)。

    1.建模为S->i容量为 a[i]-a[i-1],费用为0. 2.i->T 容量为 –(a[i]-a[i-1]),费用为0.

    对于每个人来说他会在s[i]天进入,在(t[i]+1)天或更早离开。

    3.在s[i]到t[i]+1连一条容量无限费用为c[i]的边。4.在(i+1)->i连一条容量无限费用为0的边。

    S代表进入的人,T代表着离开的人。

    最重要的是建模时的流量平衡思想。

    设Y[i]为第i天多余的人。X[i]为第i种志愿者的数量。

    对于每个点 (a[i]-a[i-1])+(Y[i]-Y[i-1])+sum(X[k1])-sum(X[k2])=0 (k1和k2满足t[k1]+1=i,s[k2]=i).

    每个点都满足这样的流量平衡

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int maxn = 1000 + 10;
    const int maxm = 100000 + 10;
    const int inf = 0x3f3f3f3f;
    
    int g[maxn],v[maxm],f[maxm],c[maxm],next[maxm],eid;
    int n,m,S,T;
    int a[maxn];
    long long res;
    LL dist[maxn];
    int pre[maxn];
    bool inque[maxn];
    int q[maxm],l,r,u;
    
    void addedge(int a,int b,int F,int C) {
        v[eid]=b; f[eid]=F; c[eid]=C; next[eid]=g[a]; g[a]=eid++;
        v[eid]=a; f[eid]=0; c[eid]=-C; next[eid]=g[b]; g[b]=eid++;    
    }
    
    void build() {
        memset(g,-1,sizeof(g));
        scanf("%d%d",&n,&m);
        S=0; T=n+2;
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1,d;i<=n+1;i++) {
            d=a[i]-a[i-1];
            if(d>=0) addedge(S,i,d,0);
            else addedge(i,T,-d,0);
        }
        for(int i=1,s,t,c;i<=m;i++) {
            scanf("%d%d%d",&s,&t,&c);
            addedge(s,t+1,inf,c);
        }
        for(int i=1;i<=n;i++) addedge(i+1,i,inf,0);
    }
    
    bool SPFA() {
        memset(dist,0x3f,sizeof(dist));
        l=r=0;
        q[r++]=S;
        dist[S]=0;
        while(l<r) {
            inque[u=q[l++]]=0;
            for(int i=g[u];~i;i=next[i]) if(f[i] && dist[v[i]]>dist[u]+c[i]) {
                dist[v[i]]=dist[u]+c[i];
                pre[v[i]]=i;
                if(!inque[v[i]]) inque[q[r++]=v[i]]=1;    
            }
        }
        return dist[T]<inf;
    }
    
    long long augment() {
        long long aug=inf,res=0;
        for(int i=T;i!=S;i=v[pre[i]^1]) aug=min(aug,(long long)f[pre[i]]);
        for(int i=T;i!=S;i=v[pre[i]^1]) {
            f[pre[i]]-=aug;
            f[pre[i]^1]+=aug;
            res+=aug*c[pre[i]];
        }
        return res;
    }
    
    void solve() {
        long long res=0;
        while(SPFA()) res+=augment();
        printf("%lld
    ",res);
    }
    
    int main() {
        build();
        solve();
        return 0;
    }
  • 相关阅读:
    gdb调试的基本使用
    重构改善代码--代码的坏味道
    17级单片机期中测试题目
    左右固定,中间自适应的三栏式布局五种写法
    存一些可能会用得到的vue的UI框架
    vue父子组件传值
    [Vue warn]: Missing required prop: "title"
    js中的值类型和引用类型的区别
    vue+node+mongoDB 火车票H5(四)---完成静态页面
    vue+node+mongoDB 火车票H5(三)---git提交时忽略不想提交的文件
  • 原文地址:https://www.cnblogs.com/invoid/p/5616245.html
Copyright © 2011-2022 走看看