负载平衡问题

难怪评蓝题,实在是太裸了。

源点向每个点连边,容量为这个点的现有货物数。

每个点向汇点连边,容量为要求即sum/n。

每个点向其相邻两点连边,容量无限,费用为1。

然后跑一遍源点到汇点的费用流。

看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf 1e12
const int maxn=1e5+10;
int n,a[maxn],sum,ans;
int beg[maxn],nex[maxn],to[maxn],w[maxn],cost[maxn],e;
queue<int>q;
inline int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    return x*f;
}
inline void add(int x,int y,int z,int c){
    nex[e]=beg[x];beg[x]=e;to[e]=y;
    w[e]=z;cost[e]=c;e++;
}
int dis[maxn],vis[maxn],las[maxn],ed[maxn],flow[maxn];
inline int spfa(){
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[0]=0;vis[0]=1;flow[0]=inf;
    las[n+1]=-1;q.push(0);
    while(!q.empty()){
        int x=q.front();
        q.pop();vis[x]=0;
        for(int i=beg[x];~i;i=nex[i]){
            int t=to[i];
            if(w[i]&&dis[t]>dis[x]+cost[i]){
                dis[t]=dis[x]+cost[i];
                las[t]=x;ed[t]=i;
                flow[t]=min(flow[x],w[i]);
                if(!vis[t]){
                    vis[t]=1;q.push(t);
                }
            }
        }
    }
    return las[n+1]!=-1;
}
signed main(){
    memset(beg,-1,sizeof(beg));
    n=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
        sum+=a[i];
    }
    for(int i=1;i<=n;i++){
        add(0,i,a[i],0);
        add(i,0,0,0);
        add(i,n+1,sum/n,0);
        add(n+1,i,0,0);
        add(i,i%n+1,inf,1);
        add(i%n+1,i,0,-1);
        add(i%n+1,i,inf,1);
        add(i,i%n+1,0,-1);
    }
    while(spfa()){
        ans+=dis[n+1]*flow[n+1];
        int tmp=n+1;
        while(tmp){
            w[ed[tmp]]-=flow[n+1];
            w[ed[tmp]^1]+=flow[n+1];
            tmp=las[tmp]; 
        }
    }
    printf("%lld\n",ans);
    return 0;
}

深深地感到自己的弱小。

posted @ 2020-04-09 21:22  syzf2222  阅读(127)  评论(0编辑  收藏  举报