题目链接:
http://www.lightoj.com/volume_showproblem.php?problem=1076
题目描述:
给出n个数,要求分成m段,问这m段中最大的总和,最小是多少?
解题思路:
二分每一段的长度,然后判定枚举长度是否合法。
刚看到这个题目就想到了dp,但是dp的复杂度还是很高的,然后就一直放着,放着。。。。学了折半枚举,拿起来一看,哇塞,简直惊喜啊!
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 8 #define LL long long 9 #define maxn 1010 10 #define mod 100000007 11 12 int n, m, a[maxn]; 13 bool bin_srea (int key) //判断key是否合法, 14 { 15 int num = 0, tmp = 0; 16 for (int i=0; i<n; i++) 17 { 18 if (a[i] > key) 19 return false; 20 if (tmp + a[i] <= key) 21 { 22 tmp += a[i]; 23 } 24 else 25 { 26 tmp = a[i]; 27 num ++; 28 } 29 } 30 return num < m; 31 } 32 33 int main () 34 { 35 int T, L = 0; 36 scanf ("%d", &T); 37 38 while (T --) 39 { 40 int l, r, ans; 41 42 l = r = 0; 43 scanf("%d %d", &n, &m); 44 for (int i=0; i<n; i++) 45 { 46 scanf ("%d", &a[i]); 47 r += a[i]; 48 l = max (l, a[i]); 49 } 50 51 while (l <= r) ///枚举每一段的长度 52 { 53 int mid = (l + r) / 2; 54 if (bin_srea(mid)) 55 { 56 ans = mid; 57 r = mid - 1; 58 } 59 else 60 l = mid + 1; 61 } 62 63 printf ("Case %d: %d\n", ++L, ans); 64 } 65 return 0; 66 }