zoukankan      html  css  js  c++  java
  • 网络流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;
    }
    
    
  • 相关阅读:
    视图的作用,视图可以更改么?
    数据库事务的四个特性及含义
    mysql 设置隔离级别
    如何避免事务的并发问题?
    事务控制语言(TCL)
    事务的并发问题有哪些?
    事务的隔离级别: 事务并发问题如何发生?
    DDL 语言
    DML 语言
    TRUNCATE、Drop、Delete 的用法
  • 原文地址:https://www.cnblogs.com/hbxblog/p/9724267.html
Copyright © 2011-2022 走看看