Description
假设有A城市通往B山区的路由m条连续的路段组成,
现在将这m条路段承包给n个工程队(n ≤ m ≤ 300)。
每个工程队只能分配到连续的若干条路段(当然也可能只分配到一条路段或未分配到路段)。
假设每个工程队修路的效率一样,即每修长度为1的路段所需的时间为1。现在给出路段的数量m,工程队的数量n,以及m条路段的长度(这m条路段的长度是按照从A城市往B山区的方向依次给出,每条路段的长度均小于1000),需要你计算出修完整条路所需的最短的时间(即耗时最长的工程队所用的时间)。
Input
第一行是测试样例的个数T ,接下来是T个测试样例,每个测试样例占2行,第一行是路段的数量m和工程队的数量n,第二行是m条路段的长度。
Output
对于每个测试样例,输出修完整条路所需的最短的时间。
Sample Input
2 4 3 100 200 300 400 9 4 250 100 150 400 550 200 50 700 300
Sample Output
400 900
分析:
百思不得其解。。。
长见识了,二分还可以这样玩~~~~~
根据条件,可能的最长时间是是 M = 1000*300
把这个值作为二分的Right,
二分查找一个时间,判断它能不能满足条件,~~~~~一直到二分结束 ,( L >= R)
用一个ans 记录能满足的最小值,最后结束后输出。
关键在于,为什么能这样做!!!!!!!!!!!!!
注意条件!!!
每个工程队的路段必须是连续的,那么也就是说,
对于一个二分出的一个确定的总时间 T,字典序枚举所有的路段,
1、如果存在某个路段的时间 > T,那么一定不行
2、如果连续枚举的路段所有花费的时间和 <= T,就一直往下加,都作为某一个队的工程
3、如果某次枚举造成 sum > T, cnt ++,需要工程队的数量加 1, 重新计算sum
4、最后比较 cnt 和 规定的 n 的大小。
/***************
* 二分查找一个花费,判断它能不能满足条件
* 一直到二分结束
************/
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int road[305];
const int MAXN_c = 300*1000+5;
int binary_find(int m, int n);
bool is_solve(int m,int n, int T);
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int m, n; // m 段路, n个工程队
scanf("%d %d",&m,&n);
for(int i = 0; i < m; i++)
scanf("%d",&road[i]);
int ans = binary_find(m, n);
printf("%d\n",ans);
}
return 0;
}
int binary_find(int m, int n)
{
int L = 0;
int R = MAXN_c;
int ans = R;
while(L < R)
{
int M = (L + R)>>1;
if(is_solve(m, n, M)) // 如果当前的总时间可以完成,那么再次减少时间试试
{
R = M;
ans = min(ans, M);
}
else // 如果不可以完成,那么增加时间
L = M + 1;
}
return ans;
}
bool is_solve(int m, int n, int T)
{
int cnt = 1; // 记录T时间所用的工程队数量
int sum = 0; // 记录一个队最多完成的工程时间
for(int i = 0; i < m; i++)
{
// 如果有一个路的花费比 T 时间长,就不成立
if(road[i] > T)
return false;
else if(sum+road[i] <= T)
{
sum += road[i];
}
else // 上一个工程队所能接的任务时间已经最大,开始下一个工程队
{
cnt ++; // 下一个工程队
sum = road[i]; // sum 重新记录
}
}
if(cnt <= n)
return true;
else
return false;
}