日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P4016 负载平衡问题

發布時間:2023/12/3 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P4016 负载平衡问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 題目描述
    • 題解:
    • 方法一:
      • 代碼:
    • 方法二:

P4016 負載平衡問題

題目描述

G 公司有 n 個沿鐵路運輸線環形排列的倉庫,每個倉庫存儲的貨物數量不等。如何用最少搬運量可以使 n
個倉庫的庫存數量相同。搬運貨物時,只能在相鄰的倉庫之間搬運。

輸入格式

第一行一個正整數 n,表示有 n 個倉庫。

第二行 n 個正整數,表示 n 個倉庫的庫存量。

輸出格式
輸出最少搬運量。

輸入輸出樣例
輸入 #1復制

5 17 9 14 16 4

輸出 #1復制

11

說明/提示
1≤n≤100。

題解:

和網絡流啥關系。。。又是老婆餅里沒老婆?

方法一:

環形均分紙牌問題,還是板子題,代碼都是通用的。。

貪心+數論
這種題總感覺在哪見過。。。
我們先考慮一種弱化的題目
n個倉庫排成一列,每個倉庫都有一定數量貨物a[i],只能相鄰倉庫可以傳遞貨物,問最少需要傳遞幾次才可以使各倉庫貨物相等?(就是把原題中的環改成一個列)
總數為sum,平均每個倉庫分到T=sum/n,b[ i ]= T - a[ i ] ( b[]表示距離標準還有多少),只要b[i]>0就說明后面一定有b[x]<0,那當前i多余的貨物就向后移動,其實也就是多退少補,最終移動總牌數
現在的問題是n個倉庫圍成一個圈,我們可以通過破圈成鏈來解決這個問題。環形均分紙牌問題可以發現一個性質:至少有兩個倉庫是不需要從彼此之間那得到卡牌,這樣就可以從這兩點破壞成鏈
如果這種方式不明白,可以看我的這個題解,有詳細分析解答
博客講解

代碼:

#include<bits/stdc++.h> using namespace std; typedef long long ll; int n; const int maxn=1e6+4; ll a[maxn]; int main() {cin>>n;ll sum=0;for(int i=1;i<=n;i++){cin>>a[i];sum+=a[i];}sum/=n;for(int i=n;i>1;i--){a[i]=sum-a[i]+a[i+1];//為啥是這個公式可以在我那個推到里面得到 }a[1]=0;sort(a+1,a+n+1);ll res=0;int mid=(n+1)/2;for(int i=1;i<=n;i++){res+=abs(a[i]-a[mid]);} cout<<res<<endl;return 0;}

方法二:

恕我才疏學淺真的是一道最小費用最大流的題目
1.源點是0,匯點是n+1,費用是指兩個相鄰倉庫中的運輸單價
2.為了讓所有倉庫都均等,我們就要讓多的倉庫送出貨物,連向源點;少的倉庫就要接受貨物,連向匯點。且連接源匯點的費用是0
3.相鄰的倉庫之間依次連上一條容量為 INF ,花費為 1 的雙向邊,
4.因為存在環的情況,所以還要特別處理1號節點與n號節點
我們用樣例做一下分析:

每個邊都有兩種顏色數字,一個表示花費,一個表示容量
源點為起點的邊容量之和等于以重點為邊容量之和
跑一邊費用流就可以了

#include <cstdio> #include <queue> #include <cstring> using namespace std; const int MAXN = 5001; const int MAXM = 50001; const int INf = 2147483647; int n, m, s, t, edge_sum = 1; int maxflow, mincost; int dis[MAXN], head[MAXN], incf[MAXN], pre[MAXN]; int a[MAXN]; bool vis[MAXN]; struct Edge {int next, to, dis, flow; }edge[MAXM << 1]; inline void addedge(int from, int to, int flow, int dis) {edge[++edge_sum].next = head[from];edge[edge_sum].to = to;edge[edge_sum].dis = dis;edge[edge_sum].flow = flow;head[from] = edge_sum; } inline bool spfa() {queue <int> q;memset(dis, -1, sizeof(dis));memset(vis, 0, sizeof(vis));q.push(s);dis[s] = 0;//距離 vis[s] = 1;// 記錄該點已詢問過 incf[s] = 0x7fffffff;//記錄路徑上的最小流 while(!q.empty()) {int u = q.front();vis[u] = 0;q.pop();for(register int i = head[u]; i; i = edge[i].next) {if(!edge[i].flow) continue;int v = edge[i].to;if(dis[v] > dis[u] + edge[i].dis||dis[v]==-1) {dis[v] = dis[u] + edge[i].dis;incf[v] = min(incf[u], edge[i].flow);pre[v] = i;//記錄前綴點 if(!vis[v]){vis[v] = 1;q.push(v);} }}}if(dis[t] == -1) return 0;return 1; } inline void EK() {while(spfa()) {int x = t;maxflow += incf[t];mincost += dis[t] * incf[t];int i;while(x != s) {i = pre[x];edge[i].flow -= incf[t];edge[i^1].flow += incf[t];//建立反向邊 x = edge[i^1].to;}} } int main() {scanf("%d", &n);int sum = 0;for(register int i = 1; i <= n; ++i) {scanf("%d",&a[i]);sum += a[i];}sum /= n;//算出平均值for(register int i = 1; i <= n; ++i) {if(a[i] < sum) {//如果需要運入就與s連邊addedge(0, i, sum - a[i], 0);addedge(i, 0, 0, 0);} else if(a[i] > sum) {//如果需要運出就與t連邊addedge(i, n + 1, a[i] - sum, 0);addedge(n + 1, i, 0, 0);}//以上為與S,T相連,以下為與臨點相連 if(i == 1) {//特判1,別忘了是無向圖addedge(1, n, INf, 1);addedge(n, 1, 0, -1);addedge(n, 1, INf, 1);addedge(1, n, 0, -1);} else {addedge(i-1, i, INf, 1);addedge(i, i-1, 0, -1);addedge(i, i-1, INf, 1);addedge(i-1, i, 0, -1);}}s = 0, t = n + 1;EK();printf("%d\n",mincost);return 0; }

總結

以上是生活随笔為你收集整理的P4016 负载平衡问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。