• 洛谷P4016 负载平衡问题 费用流


    这道题还是很好的.

    考察了选手对网络流的理解.

    首先,任意两个相邻点之间的运货量时没有限制的.

    我们可以将相邻点之间的流量建为无限大,单位费用设为 1,代表运输一个货物需耗费一个代价.

    由于题目要求最后所有人的货物量都相同,则说明每个人在最后拥有的货物量一定是总货物量的平均数,我们设为 $w$.

    考虑一个点开始是的货物量为 $a$,则讨论两种情况.

    1. a > w,则说明 $a$ 需要向周围的站点送出 $a-w$ 个货物以达到供需平衡. 我们从源点向该点流进 (a-w) 的流量,费用为 0 

    2. a < w,则说明该点需要得到 $w - a$ 个货物的补给,那么就让该点向汇点流出 (w-a) 的流量,费用仍然为 0.

    我们思考一下,为什么这样是对的 ? 

    我们发现,所有点 (a-w) 之和一定为 0. (因为总量是守恒的)

    首先,考虑第一种情况.

    由于一个点被源点流进了 $a-w$ 的流量,那么该点一定会流出 $a-w$ 的流量,那么该点会至少贡献 $a-w$ 的花费.

    由于流量是可以流满的,所以该做法就是正确的

    Code:

    #include<cstdio>              //好题
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int maxn=500;
    const int INF=1000000+23666;
    typedef long long ll;
    int A[maxn];
    int s,t,n;
    struct Edge{
    	int from,to,cap,cost;
    	Edge(int u,int v,int c,int f):from(u),to(v),cap(c),cost(f){}
    };
    struct MCMF{
        vector<Edge>edges;
        vector<int>G[maxn];
        int d[maxn],inq[maxn],a[maxn],flow2[maxn];
        queue<int>Q;
        ll ans=0;
        int flow=0;
        void addedge(int u,int v,int c,int f){
        	edges.push_back(Edge(u,v,c,f));    //正向弧
        	edges.push_back(Edge(v,u,0,-f));   //反向弧
        	int m=edges.size();
        	G[u].push_back(m-2);
        	G[v].push_back(m-1);
        }
        int SPFA(){
        	for(int i=0;i<=n;++i)d[i]=INF,flow2[i]=INF;
        	memset(inq,0,sizeof(inq));int f=INF;
        	d[s]=0,inq[s]=1;Q.push(s);
            while(!Q.empty()){
            	int u=Q.front();Q.pop();inq[u]=0;
            	int sz=G[u].size();
            	for(int i=0;i<sz;++i){
                      Edge e=edges[G[u][i]];
                      if(e.cap>0&&d[e.to]>d[u]+e.cost){
                          a[e.to]=G[u][i];
                          d[e.to]=d[u]+e.cost;
                          flow2[e.to]=min(flow2[u],e.cap);
                          if(!inq[e.to]){inq[e.to]=1;Q.push(e.to);}
                      }
            	}
            }
            if(d[t]==INF)return 0;
            f=flow2[t];
            flow+=f;
            int u=edges[a[t]].from;
            edges[a[t]].cap-=f;
            edges[a[t]^1].cap+=f;
            while(u!=s){
            	edges[a[u]].cap-=f;
            	edges[a[u]^1].cap+=f;
            	u=edges[a[u]].from;
            }
            ans+=(ll)(d[t]*f);
            return 1;
        }
        ll maxflow(){
            while(SPFA());
            return ans;
        }
       // ll getcost(){return ans;}
    }op;
    int main()
    {
         int N;scanf("%d",&N);
         s=0,t=N+1,n=N+1;
         int sum=0,ave;
         for(int i=1;i<=N;++i){
              int a;scanf("%d",&a);
              A[i]=a;
              sum+=a;
         }
         ave=sum/N;
         for(int i=1;i<=N;++i)
         {
              int a=A[i]-ave;
              if(a>0)op.addedge(s,i,a,0);
              if(a<0)op.addedge(i,t,-a,0);
         }
         for(int i=2;i<N;++i)
         {
         	     op.addedge(i,i-1,INF,1);
         	     op.addedge(i,i+1,INF,1);
         }
         op.addedge(1,2,INF,1);
         op.addedge(1,N,INF,1);
         op.addedge(N,N-1,INF,1);
         op.addedge(N,1,INF,1);
         printf("%lld",op.maxflow());
         return 0;
    }
    

      

  • 相关阅读:
    Qual IPE中的Crop计算
    TinyCC安装
    C编译器(TCC)
    Macros之PRId64
    shell脚本学习 (10) 从结构化文本提取数据
    shell脚本学习 (9) 提取开头或结尾的几行
    shell脚本学习 (8) fmt 格式化段落
    接触python的第2天:了解变量和打印
    接触python的第1天:测试hello world
    shell脚本学习(7)sort
  • 原文地址:https://www.cnblogs.com/guangheli/p/10367601.html
Copyright © 2020-2023  润新知