- 平衡负载
- Du熊正在负责一个大型的项目,目前有K台服务器,有N个任务需要用这K台服务器来完成,所以要把这些任务分成K个部分来完成,在同上台服务器上执行的任务必须是连续的任务,每个任务有各自需要的执行时间。
- 例如N=5,K=2,每个任务需要时间分别为5,3,1,4,7分钟,那么我们可以分成(5)(3 1 4 7)两部分,这样第一台服务器所花时间就是5分钟,而第二台机器需要花15分钟,当然,所有任务完成的时间是按最迟完成的那台服务器的时间,即这样划分的话完成所有任务所需要的时间就是15分钟。而另外一种划分方法是(5 3 1)(4 7),这种划分方案完成所有任务的时间就是11分钟,也是最优的一种划分方案。
- 现在你的任务就是根据给定的N,K和每个任务要花费的时间,找出使完成所有任务时间最短的方案。
- 输入:
- 多组输入。
- 第一行输入N和K(1<=K<=N<=10000)。
- 第二行输入N个不大于1000的正整数,表示各个任要花费的时间。
- N=K=0表示输入结束。
- 输出:
- 每行输出一个整数,对应对于每个数据(除了N=K=0不用输出)。
- 样例输入:
- 5 1
- 5 3 1 4 7
- 5 2
- 5 3 1 4 7
- 5 3
- 5 3 1 4 7
- 10 3
- 1 2 3 4 5 6 7 8 9 10
- 0 0
- 样例输出:
- 20
- 11
- 8
- 21
解答思路:最优划分用动态规划解决,我认为其中比较关键的是
1)如何转化问题,即使用符号表示待解决的问题。
本题中,设f(i,k)表示数组a[i…N]分成k部分的最优值。
2)状态转移方程。
本题为f(i,k)=min(j)max{f(j,k-1), sum(i, j-1)}, i < j <= N-k+2 ,k = 2,…,K.
3)初始状态的确定。
本题为f(i,1) = sum(i, N), i = 1,...,N.即k=1为初始状态。
Ps:我觉得做动态规划的时候,最好还是找一个小规模问题,列一个表计算一下,就能把握i,j,k的范围和加深对题目解答的理解,切记切记!
#include <stdio.h> #define MIN(a,b) (a)<(b)?(a):(b) #define MAX(a,b) (a)>(b)?(a):(b) int a[1001]; int f[1001][1001]; int tmpMax[1001]; int sum(int i, int j) { int s = 0; for (int k = i; k <= j; k++) { s+= a[k]; } return s; } int main() { int N, k; scanf("%d %d",&N,&k); do { int i = 1;; while (i<=N) { scanf("%d", &a[i]); i++; } //f[i][k]表示a[i...N] 分成k 部分的最优划分方案 for (int i = 1; i <= N; i ++) { f[i][1] = sum(i,N); } //DP int tmpmin; for (int nk = 2; nk <= k; ++nk) { for (int i = 1; i < N - nk + 2; i++) { tmpmin = 0x7FFFFFFF; for (int j = i+1; j <= N - nk + 2; j++) { //对每个j,比较f[j][nk-1] 和sum(i,j-1)两部分的最大值 tmpMax[j] = -1; tmpMax[j] = MAX(f[j][nk-1], sum(i,j-1)); //对所有的j的最大值,取最小值即为f[i][nk] tmpmin= MIN(tmpmin,tmpMax[j]); } f[i][nk] = tmpmin; } } printf("%d\n",f[1][k]); scanf("%d %d",&N,&k); } while (N != 0 && k != 0); }