平衡負載
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
思路:
初看這個題目,覺得可以用dfs來做,不過效率肯定是比較低的,所以后來想想,其實這道題目挺符合dp使用條件的,有這重復的子問題,有這最優子結構和無后效性,所以就打算用dp做了,首先定義狀態dp[x][y],表示將前y個任務分到前x台服務器,完成前y個任務的最短時間。狀態轉移方程為:
dp[x][y] = min{max{dp[x - 1][y1] , sy}} 其中y1取值為[x - 1, y - 1],sy = time[y1 + 1] + time[y2 + 1] + ...+time[y]
如果直接定義dp[10000][10000],那空間太大了,通過狀態轉移方程可以知道,dp[x][y]只與dp[x - 1][y1]有關,所以可以定義dp[2][10000]來節省空間。代碼如下:
1 #include <stdio.h> 2 3 #define max(a, b) a > b ? a : b 4 int n, k; 5 int time[10005]; 6 int dp[2][10005]; 7 int temp[10005]; 8 9 int main(void) 10 { 11 int i, j, min, l; 12 13 while (scanf("%d%d", &n, &k), n && k) 14 { 15 for (i = 1; i <= n; i ++) 16 scanf("%d", &time[i]); 17 dp[1][1] = time[1]; 18 for (i = 2; i <= n; i ++) 19 dp[1][i] = dp[1][i - 1] + time[i]; 20 for (j = 2; j <= k; j ++) 21 { 22 for (i = j; i <= n; i ++) 23 { 24 min = 100000000; 25 temp[0] = 0; 26 for (l = i - 1; l >= j - 1; l --) 27 { 28 temp[i - l] = temp[i - l - 1] + time[l + 1]; 29 if (max(dp[(j + 1) % 2][l] , temp[i - l]) < min) 30 min = max(dp[(j + 1) % 2][l] , temp[i - l]); 31 } 32 dp[j % 2][i] = min; 33 printf("%d ", dp[j % 2][i]); 34 } 35 printf("\n"); 36 } 37 printf("%d\n", dp[k % 2][n]); 38 } 39 return 0; 40 }