LightOJ 1048 - Conquering Keokradong(二分)

来源:互联网 发布:淘宝裸根月季苗 编辑:程序博客网 时间:2024/05/22 04:33

This winter we are going on a trip to Bandorban. The main target is to climb up to the top of Keokradong. So, we will use a trail. The trail is a continuous marked footpath that goes from Bandorban to Keokradong.

Part of the experience is also the route planning of the trip. We have a list of all possible campsites that we can use along the way and we want to do this trip so that we only stop K nights to camp. We also know in advance the distance between consecutive campsites and we are only allowed to camp at a campsite. Our goal is to plan the trip so that we minimize the maximum amount of walking done in a single day. In other words, if our trip involves 2 nights (3 days of walking), and we walk 9, 10, 5 miles on each day respectively, the cost (maximum amount of walking done in one day) is 10. Another schedule that involves walking 9, 6, 9 miles on each day has cost 9.

Given the distances between N consecutive campsites of a trail and given the number of nights for your trip, K, your task is to devise a camping strategy for the specified trail such that it minimizes the maximum amount of walking done in a single day. Note that the first distance value given is the distance from our start-point of the trail to our 1st campsite, and the last distance value given is the distance from our Nth campsite to our end-point of the trail.

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case contains of two integers, the number of campsites, N (1 ≤ N ≤ 1000) and the number of nights of the trip, K (1 ≤ K ≤ min(N, 300)). The following N + 1 lines indicate the distance in miles between consecutive campsite locations. All the integers will be positive and less than 10000.

Output
For each case of input you have to print the case number and the minimized cost as described above. Then print K+1 lines, each containing the amount of distance covered in ith day. As there can be many solutions, the primary target is to find the one which ensures that each day we have to walk some distance. For ties, print the one where the distance covered in first day is maximum, then the distance covered in second day is maximum and so on.

Sample Input
Output for Sample Input
1
4 3
7
2
6
4
5
Case 1: 8
7
8
4
5

题意:
给出n,m;将n+1 个有序的数分成m+1组。每个组的值为这个组里所有数的和。要求使这(m+1)个组中最大的那个值 最小。输出这个值和每个组的值。如果有相同答案,那么靠的组值尽量大。

分析:
我们需要输出怎么分组的,那么就必须知道这个max是多少,不然无从下手。因此我们想到了要先枚举这个max。而需要这个max尽量小,又可求出出这个max的上界和下界[max(a[i]),sum(a[i])],于是可以二分答案。

二分很好想,这道题的主要困难还是在输出分组情况上面。
因为必须分成(M+1)组,所以就有可能后面的几组数远远填不满这个max。
看这几组数据就明白了:

Input:16 410555555Output:Case 1: 101010105524 251 1115 4515111Case 1: 5531Case 2: 55152126 46777325558104 4183465767

收获:
算法虽然简单,但在实现的时候应多注意细节qwq

#include <cstdio>#include <cstring>#include <cmath>#include <iostream>#include <algorithm>using namespace std;int m,n,t,a[1005],ans,flag,tot;bool can(int v){    int k=0,now=0,flag=0;    for(int i=1;i<=n;i++)    {        if ( (a[i]+now <=v) && (n-i)>=(m-k-1) ) now+=a[i];        else {            now=a[i];            k++;            if(k>=m || a[i]>v) return false;        }    }    return true;}int erfen(int l,int r){    if(l==r) return l;    int mid=(l+r) >> 1;    if(can(mid)) return erfen(l,mid);    else return erfen(mid+1,r);}int print(){    int now=0,pp=0;    for(int i=1;i<=n;i++)    {        if ((a[i]+now<=ans) && (n-i)>=(m-pp-1) ) now+=a[i];        else         {            printf("%d\n",now);            now=a[i];            pp++;        }    }    // cout<<pp<<endl;     printf("%d\n",now);    return 0;}int main(){    freopen("in.txt","r",stdin);    scanf("%d\n",&t);    for(int k=1;k<=t;k++)    {        scanf("%d %d",&n,&m);        n++;m++;tot=0;        for(int i=1;i<=n;i++)        {            scanf("%d",&a[i]);            tot+=a[i];        }        ans=erfen(a[1],tot);        printf("Case %d: %d\n",k,ans);        // cout<<n<<endl;        print();    }    return 0;}
0 0
原创粉丝点击