POJ 3273 Monthly Expense

题目大意:

        农场主John是一个做账的奇才,他意识到自己快把所有钱都要花销在经营农场上了。幸好他已经将未来N天(1 ≤ N ≤ 100,000)的每天的开销都做了计算,每天花的钱的范围为[1, 10,000]。他做了一个预算,将未来N天分为M个阶段(1 ≤ M ≤ N),每个阶段包含连续的若干天,每一天都包含在某一阶段中。

        现只有一个测例,测例中给出N和M,以及N天中每一天的开销,先求出如果分为M个阶段则最大的阶段开销为多少。

题目链接

注释代码:

/*                                    
 * Problem ID : POJ 3273 Monthly Expense
 * Author     : Lirx.t.Una                                    
 * Language   : C++                   
 * Run Time   : 63 ms                                    
 * Run Memory : 556 KB                                    
*/  

#include <stdio.h> 

#define	TRUE		1
#define	FALSE		0

//maximum number of days
//预算的最大天数(数组下标取到100,000)
#define	MAXDAYN		100001

typedef	int		BOOL;

int		ep[MAXDAYN];//expense of each day,每天的开销

BOOL
xlim( int d, int n, int m ) {
	//d为假设的每个阶段的开支上限
	//n为天数
	//m为指定的阶段数
	
	//count为d上限条件下最少的阶段数,sum记录当前阶段的开支
	int		cnt, sum;
	int		i;//计数变量
	
	for ( cnt = 1, sum = 0, i = 1; i <= n; i++ ) {
		
		sum += ep[i];
		
		if ( sum > d ) {//超出上限就加一组
			
			cnt++;
			sum = ep[i];//将当前天的开支初始化下一阶段的开支
		}
	}
	
	if ( cnt > m )//上限太小导致可分的阶段数太多,因此需要提高上限
		return FALSE;
	else//分组数不够,表示上限太高,减小
		return TRUE;
}

int
main() {
	
	int		n, m;//天数和阶段数
	int		i;//计数变量
	int		max;//最大开支
	int		sum;//总开支
	
	//[lft, rht]阶段开支的可能范围
	//mid为区间中点
	//用mid来逼近最终的答案
	int		lft, rht, mid;
	
	scanf("%d%d", &n, &m);
	
	for ( sum = 0, max = 0, i = 1; i <= n; i++ ) {
		
		scanf("%d", ep + i);
		
		sum += ep[i];
		if ( ep[i] > max )
			max = ep[i];
	}
	
	if ( 1 == m ) {//如果只分一个阶段则结果就是总开支
		
		printf("%d\n", sum);
		return 0;
	}
	
	if ( n == m ) {//如果阶段数等于天数则结果就是最大开支
		
		printf("%d\n", max);
		return 0;
	}
	//以上可以避免特殊情况下的二分搜索,以降低运行时间
	
	//区间初始化
	lft = max;//由于max一定包含在某阶段中,因此阶段最低预算一定大于等于max
	rht = sum;//极端情况(只有一个阶段的情况)
	
	while ( lft <= rht ) {
		
		mid = ( lft + rht ) >> 1;
		
		if ( !xlim( mid, n, m ) )
			lft = mid + 1;
		else
			rht = mid - 1;
	}
	
	printf("%d\n", mid);
	
	return 0;
}

无注释代码:

#include <stdio.h> 

#define	TRUE		1
#define	FALSE		0

#define	MAXDAYN		100001

typedef	int		BOOL;

int		ep[MAXDAYN];

BOOL
xlim( int d, int n, int m ) {
	
	int		cnt, sum;
	int		i;
	
	for ( cnt = 1, sum = 0, i = 1; i <= n; i++ ) {
		
		sum += ep[i];
		
		if ( sum > d ) {
			
			cnt++;
			sum = ep[i];
		}
	}
	
	if ( cnt > m )
		return FALSE;
	else
		return TRUE;
}

int
main() {
	
	int		n, m;
	int		i;
	int		max;
	int		sum;
	
	int		lft, rht, mid;
	
	scanf("%d%d", &n, &m);
	
	for ( sum = 0, max = 0, i = 1; i <= n; i++ ) {
		
		scanf("%d", ep + i);
		
		sum += ep[i];
		if ( ep[i] > max )
			max = ep[i];
	}
	
	if ( 1 == m ) {
		
		printf("%d\n", sum);
		return 0;
	}
	
	if ( n == m ) {
		
		printf("%d\n", max);
		return 0;
	}
	
	lft = max;
	rht = sum;
	
	while ( lft <= rht ) {
		
		mid = ( lft + rht ) >> 1;
		
		if ( !xlim( mid, n, m ) )
			lft = mid + 1;
		else
			rht = mid - 1;
	}
	
	printf("%d\n", mid);
	
	return 0;
}

单词解释:

expense:n, 开支

astounding:adj, 令人震惊的

wizard:n, 术士,奇才,男巫

accounting:n, 会计,账单

run out of:vt, 用完

budget:n, 预算

sequential:adj, 连续的,相继的

fiscal:adj, 会计的,财政、国库的

schedule:vt, 计划,安排

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值