poj 3273/1064/2456 二分答案(Monthly Expense)

3273:

题意:给出n个数,要求把这n个数顺序不变的分成m组(即每组数必然是连续的)。要求分组后各组的花费之和的最大值尽可能地小,并求这个最小值。

思路:二分答案。也就是每次设定一个最小值,看看分成m组是否能够达到。如果分组多于m,则说明mid偏小,否则说明mid偏大。

#include <stdio.h>
#include <string.h>
#define max(a,b) ((a)<(b)?(b):(a))
#define N 100005
int s[N];
int n,m;
int main(){
	freopen("a.txt","r",stdin);
	while(scanf("%d %d",&n,&m)!=EOF){
		int i,low,high,mid,num,sum;
		low = high = 0;
		for(i = 0;i<n;i++){
			scanf("%d",&s[i]);
			low = max(low,s[i]);//关键点之一,low如果从0开始则会出现错误
			high += s[i];
		}
		while(low <= high){
			mid = (low+high)>>1;
			num = sum = 0;
			for(i = 0;i<n;i++){
				sum += s[i];
				if(sum > mid){
					num ++;
					sum = s[i];
				}
			}
			num++;//加上最后一天的组
			if(num > m)
				low = mid+1;
			else
				high = mid-1;
		}
		printf("%d\n",low);
	}
	return 0;
}

1064:

题意:给定一系列电缆的长度,需要截取成等长的m份,求所能截取的最大长度值。

思路:二分答案。注意为了避免用double,将题目中给出的小数都乘以100以变成整数再来计算即可。

2456也是同样的思路

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <map>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define N 10005
int n,m;
int s[N];
int test(int x){
    int i,res=0;
    for(i = 0;i<n;i++)
        res += s[i]/x;
    return res;
}
int main(){
    int i,j,a,b;
    int low,high,mid;
    scanf("%d %d",&n,&m);
    for(i = high = 0;i<n;i++){
        scanf("%d.%d",&a,&b);
        s[i] = a*100+b;
        high = max(high,s[i]);
    }
    low = 1;
    while(low <= high){
        mid = (low+high)>>1;
        j = test(mid);
        if(j >= m)
            low = mid+1;
        else
            high = mid-1;
    }
    if(high < 1)
        printf("0.00\n");
    else
        printf("%d.%.2d\n",high/100,high%100);
    return 0;
}


你可能感兴趣的:(poj 3273/1064/2456 二分答案(Monthly Expense))