网络流24题之负载平衡问题

题目链接:传送门

初次看这道题是不是发现这道题和均分纸牌很像,只是一个是环一个是链而已,所以这道题明显可以贪心啊,但是因为这是网络流24题,所以还是把它当做网络流的题目来做吧

这是一道费用流的题目,首先老规矩建立一个源点,汇点
为什么要建啊?,问这个问题有两种可能性
1.太强,请移步至传送门
2.太弱,请移步至传送门

怎么连接汇点和源点呢?贪心的想一下,要使所有仓库数量相等,所以应将多的仓库运往少的仓库,所以多的仓库应该贡献,连向源点。少的仓库应该得到,连向汇点,且费用为0。然后相邻节点有一条流量为inf,费用为1的边(注意这里为无向边)

再来回到开始说所得这是一个环不是一个链,所以要特殊处理一下1和n节点

#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=10001;
queue<int> q;
int dis[N],f[N],pre[N],fa[N],head[N],cnt,n,m,s,t,x,y,z,w,ans,ans1,b[N];
struct node {
    int to,next,v,w;
} a[100001];
void add(int x,int y,int c,int v) {
    a[++cnt].to=y;
    a[cnt].next=head[x];
    a[cnt].v=c;
    a[cnt].w=v;
    head[x]=cnt;
}
int spfa() {
    memset(dis,127,sizeof(dis));
    memset(f,0,sizeof(f));
    q.push(s);
    f[s]=1;
    int inf=dis[1];
    dis[s]=0;
    while(!q.empty()) {
        int now=q.front();
        q.pop();
        f[now]=0;
        for(int i=head[now]; i; i=a[i].next) {
            int v=a[i].to;
            if(dis[v]>dis[now]+a[i].w&&a[i].v) {
                dis[v]=dis[now]+a[i].w;
                fa[v]=now;
                pre[v]=i;
                if(!f[v])
                    q.push(v),f[v]=1;
            }
        }
    }
    if(dis[t]!=inf)
        return 1;
    return 0;
}
void answer() {
    while(spfa()) {
        int minx=2147483647;
        for(int i=t; i!=s; i=fa[i])
            minx=min(minx,a[pre[i]].v);
        ans1+=dis[t]*minx;
        for(int i=t; i!=s; i=fa[i]) {
            a[pre[i]].v-=minx;
            if(pre[i]%2)
                a[pre[i]+1].v+=minx;
            else
                a[pre[i]-1].v+=minx;
        }
    }
}
int main() {
    scanf("%d",&n),ans=0,t=n+1;
    for(int i=1;i<=n;i++)
        scanf("%d",&b[i]),ans+=b[i];
    for(int i=1;i<=n;++i)
        b[i]-=ans/n;
    for(int i=1;i<=n;++i){
        if(b[i]>0)
            add(s,i,b[i],0),add(i,s,0,0);
        else if(b[i]<0)
            add(i,t,-b[i],0),add(t,i,0,0);
    }
    for(int i=1;i<n;i++)
        add(i,i+1,100000000,1),add(i+1,i,0,-1),add(i+1,i,10000000,1),add(i,i+1,0,-1);
    add(n,1,ans,1),add(1,n,0,-1);
    add(1,n,ans,1),add(n,1,0,-1);
    answer();
    printf("%d",ans1);
    return 0;
}

posted @ 2018-09-29 16:12  撤云  阅读(219)  评论(0编辑  收藏  举报
……