生活随笔
收集整理的這篇文章主要介紹了
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
) {addedge(0, i
, sum
- a
[i
], 0);addedge(i
, 0, 0, 0);} else if(a
[i
] > sum
) {addedge(i
, n
+ 1, a
[i
] - sum
, 0);addedge(n
+ 1, i
, 0, 0);}if(i
== 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 负载平衡问题的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。