zoukankan      html  css  js  c++  java
  • [SDOI2011][bzoj2245] 工作分配 [费用流]

    题面

    传送门

    思路

    数据范围n,m<=250

    分配任务问题

    这是典型的“看到数据范围就知道算法”类型

    而且我们发现我们要保证一定产出的情况下最小化花费

    这句话等价于保证一定流量的情况下最小化费用

    所以先确定算法:最小费用最大流

    再观察一下,我们发现这道题的费用和人唯一相关,而且人和物品之间的关系是独立的

    因此我们建立一个网络流图,其中包含S,T,人点和物品点

    对于每个物品i,我们连边(i,T),费用0,流量为$C_i$

    对于一个人i可以操作物品j,我们连边(i,j),费用0,流量inf

    接下来的问题就是处理人的费用了

    我们发现这道题的费用是分段处理的

    看到分段,第一想法就是把人拆点,但是这样势必会大大增加冗余边数,拖慢程序速度

    因此我们考虑不拆点来做

    观察发现,这道题分段中保证$W_{i,j}$递增

    也就是说,如果有一坨重边,我们的算法会先跑代表靠前的分段的边

    这引导我们往重边方向上想

    对于一个点i,我们把每个长度为l,段中费用为cost的分段,连一条边(S,i),费用cost,流量l

    因为每个点最多六段,所以这个算法的边数很少,跑得过

    最后只要一步(S,T)费用流,输出总费用就可以了

    Code:

    这题卡常数啊......

    而且我的zkw费用流被卡了过不了,洛谷评测机又不稳定,一会TLE一会RE的......

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define inf 1e9
    #define ll long long
    using namespace std;
    inline ll read(){
        ll re=0,flag=1;char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-') flag=-1;
            ch=getchar();
        }
        while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
        return re*flag;
    }
    ll first[5010],dis[5010],vis[5010],n,m,cnt=-1,ans;
    struct edge{
        ll to,next,w,cap;
    }a[600010];
    inline void add(ll u,ll v,ll w,ll cap){
        a[++cnt]=(edge){v,first[u],w,cap};first[u]=cnt;
        a[++cnt]=(edge){u,first[v],-w,0};first[v]=cnt;
    }
    ll q[1000010];
    ll limit[5010],pre[5010];
    bool Spfa(int s,int t){
        ll head=0,tail=1,i,u,v,w;
        memset(dis,-1,sizeof(dis));memset(vis,0,sizeof(vis));
        memset(limit,0,sizeof(limit));memset(pre,-1,sizeof(pre));
        q[0]=s;dis[s]=0;vis[s]=1;limit[s]=inf;
        while(head<tail){
            u=q[head++];vis[u]=0;
            for(i=first[u];~i;i=a[i].next){
                v=a[i].to;w=a[i].w;
                if(a[i].cap&&((dis[v]==-1)||(dis[v]>dis[u]+w))){
                    dis[v]=dis[u]+w;pre[v]=i;
                    limit[v]=_min(limit[u],a[i].cap);
                    if(!vis[v]) q[tail++]=v,vis[v]=1;
                }
            }
        }
        return ~dis[t];
    }
    int mcmf(int s,int t){
        int re=0,u;
        while(Spfa(s,t)){
            re+=limit[t];
            for(u=t;~pre[u];u=a[pre[u]^1].to){
                a[pre[u]].cap-=limit[t];a[pre[u]^1].cap+=limit[t];
                ans+=limit[t]*a[pre[u]].w;
            }
        }
        return re;
    }
    int main(){
        memset(first,-1,sizeof(first));
        m=read();n=read();ll i,j,t1,t2[10],t3;
        for(i=1;i<=n;i++) t1=read(),add(0,i,0,t1);
        for(i=1;i<=m;i++){
            for(j=1;j<=n;j++){
                t1=read();
                if(t1) add(j,n+i,0,inf);
            }
        }
        for(i=1;i<=m;i++){
            t1=read();t2[0]=0;
            for(j=1;j<=t1;j++) t2[j]=read();
            for(j=0;j<t1;j++){//分段建重边
                t3=read();
                add(n+i,n+m+1,t3,t2[j+1]-t2[j]);
            }
            t3=read();add(n+i,n+m+1,t3,inf);
        }
        mcmf(0,n+m+1);
        cout<<ans<<endl;
    }
    
  • 相关阅读:
    wpf 获取datagrid中模板中控件
    WPF DataGrid DataGridTemplateColumn 控制模板中控件
    ztree实现拖拽移动和复制
    layui的select监听
    layui父页面获取子页面数据
    win10安装网络适配器
    bat启动OpenOffice4
    java注解简单使用
    win7安装IIS
    java的Array和List相互转换
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/8745373.html
Copyright © 2011-2022 走看看