zoukankan      html  css  js  c++  java
  • 洛谷P4016 负载平衡问题(费用流)

    题目

    https://www.luogu.com.cn/problem/P4016

    思路

    这题是网络流24题中的一道相对简单的题。既然是网络流题,我们先考虑怎么建图。

    读入各仓库货物数(a[i])求出平均值(frac{sum}{n}),我们就知道每一个仓库需要调入/调出多少货物,令(f(i)=a[i]-frac{sum}{n})

    新建一个源点S和一个汇点T,对于任意的(i),若(f(i)>0),说明该仓库要向其他仓库调出货物,我们加入一条从S到(i)的边,边权为0,容量为(f(i))。可以看成本来没有东西,源点S通过这条边给了它(f(i))个。它必须要把这(f(i))个流走。

    同理,若(f(i)<0),说明该仓库要从其他仓库调入货物,我们加入一条从(i)到T的边,边权为0,容量为(-f(i))。可以看成本来是负的,只有满足了这条边,才说明有其他仓库流向它将其补为0。

    至于环内的边,没有限制,随便流,一定是满足负载平衡的。将每一个点与其相邻点连边,边权为1,容量为无穷。

    图片可以帮助理解:

    跑一遍最小费用最大流就ok了。图片只是示例,写代码的时候不要忘记处理反向边。

    代码

    #include<cstdlib>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define inf 0x3f3f3f3f
    using namespace std;
    int n,fst[110],nxt[1000],cnt=0,a[101],book[110],dis[110],pre[110];
    struct edge{
        int u,v,w,cap;
    } e[1000];
    void add(int x,int y,int z,int k){
        e[++cnt].u=x;
        e[cnt].v=y;
        e[cnt].w=z;
        e[cnt].cap=k;
        nxt[cnt]=fst[x];
        fst[x]=cnt;
    }
    int spfa(){
        int i;
        queue<int> q;
        memset(book,0,sizeof(book));
        memset(dis,inf,sizeof(dis));
        dis[0]=0;book[0]=1;
        q.push(0);
        while(!q.empty()){
            int p=q.front();
            for(i=fst[p];i;i=nxt[i]){
                if(e[i].cap<=0) continue;
                if(dis[e[i].v]>dis[p]+e[i].w){
                    dis[e[i].v]=dis[p]+e[i].w;
                    pre[e[i].v]=i;
                    if(!book[e[i].v]){
                        book[e[i].v]=1;
                        q.push(e[i].v);
                    }
                }
            }
            book[p]=0;
            q.pop();
        }
        if(dis[n+1]<inf) return 1;
        else return 0;
    }
    int inv(int x){
        if(x&1) return x+1;
        else return x-1;
    }
    int dinic(){
        int i,ans=0;
        while(spfa()){
            int flow=inf;
            for(i=n+1;i;i=e[pre[i]].u)
                flow=min(e[pre[i]].cap,flow);
            for(i=n+1;i;i=e[pre[i]].u){
                e[pre[i]].cap-=flow;
                e[inv(pre[i])].cap+=flow;
            }
            ans+=flow*dis[n+1];
        }
        return ans;
    }
    int main(){
        int i,j,x,sum=0,ans;
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            sum+=a[i];
        }
        for(i=1;i<=n;i++){
            x=a[i]-sum/n;
            if(x<0){
                add(i,n+1,0,-x);
                add(n+1,i,0,0);
            }
            if(x>0){
                add(0,i,0,x);
                add(i,0,0,0);
            }
        }
        for(i=1;i<=n;i++){
            add(i,i%n+1,1,inf);
            add(i%n+1,i,-1,0);
            add(i,(i-2+n)%n+1,1,inf);
            add((i-2+n)%n+1,i,-1,0);
        }
        printf("%d",dinic());
        system("pause");
        return 0;
    }
  • 相关阅读:
    系统设计的一些原则
    分层开发思想与小笼包
    工作与生活
    Microsoft .NET Pet Shop 4 架构与技术分析
    用人之道(二) 如何管理软件开发团队
    也谈很多开发人员的毛病
    《3S新闻周刊》第10期,本期策划:“超女”营销带来的启示
    浅析ArcIMS
    MapX的坐标问题
    应用ArcIMS构建GMap风格的地图应用
  • 原文地址:https://www.cnblogs.com/landmine-sweeper/p/14030021.html
Copyright © 2011-2022 走看看