poj3273 二分 易错题

Monthly Expense
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 29665 Accepted: 11263

Description

Farmer John is an astounding accounting wizard and has realized he might run out of money to run the farm. He has already calculated and recorded the exact amount of money (1 ≤ moneyi ≤ 10,000) that he will need to spend each day over the next N (1 ≤ N ≤ 100,000) days.

FJ wants to create a budget for a sequential set of exactly M (1 ≤ M ≤ N) fiscal periods called "fajomonths". Each of these fajomonths contains a set of 1 or more consecutive days. Every day is contained in exactly one fajomonth.

FJ's goal is to arrange the fajomonths so as to minimize the expenses of the fajomonth with the highest spending and thus determine his monthly spending limit.

Input

Line 1: Two space-separated integers:  N and  M 
Lines 2.. N+1: Line  i+1 contains the number of dollars Farmer John spends on the  ith day

Output

Line 1: The smallest possible monthly limit Farmer John can afford to live with.

Sample Input

7 5
100
400
300
100
500
101
400

Sample Output

500

题意:n组数据分为连贯的5组,求其中最大值的最小值。

分析:
二分money找到一个值d,然后判断C(d);
C(d):在money为d的限制条件下,判断是否能够成功分组;

程序要考虑到三种极限情况:
1.[a,b] a行b不行,使用while(ub-lb)时可能会WA
2.[a,b] a不行b行,使用while(ub>lb)时可能会超时
3.[a,b,c] 其中a不行b行,使用ub = mid-1+ub>lb时可能会得出错误答案
考虑到以上三种情况并不容易,我前几次ac的代码在考虑3中都找出了反例.比如第3种极限情况:
4 3 
1 2 2 3
很多网友的ac代码,包括我自己之前的ac代码都过不了这类数据。

方法一:1到m遍历,看能否m次恰好把n个值分完。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <bitset>
#include <list>
#include <sstream>
#include <set>
#include <functional>
using namespace std;

#define INF 0x3f3f3f3f
#define MAX 100
typedef long long ll;
int n,m;
int x[100005];

bool C(int d)
{
	int id = 0;
	for (int i = 0; i < m; i += 1){
		int sum = 0;
		while (sum+x[id]<d && id<n){
			sum += x[id];
			id++;
		}
	}
	if(id<n) return true;//没走完,分组大于m组,mid太小
	return false; 
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
	
	cin >> n >> m;
	int lb = 0,ub = 0;
	for (int i = 0; i < n; i += 1){
		cin >> x[i];
		lb = max(lb,x[i]);
		ub = ub+x[i];
	}
	while (ub-lb>1){
		int mid = (ub+lb)/2;
		if(C(mid)) lb = mid;//mid太小,右移
		else ub = mid;
	}
	printf("%d\n",lb);
	return 0;
}

方法二:1到n进行分组,看n个值是否能分为m组。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <bitset>
#include <list>
#include <sstream>
#include <set>
#include <functional>
using namespace std;

#define INF 0x3f3f3f3f
#define MAX 100
typedef long long ll;
int n,m;
int x[100005];

bool C(int d)
{
	int sum = 0,ans = 1;
	for (int i = 0; i < n; i += 1){
		sum += x[i];
		if(sum > d){
			ans++;//ans只加了m-1次,最后一次不会满足这个条件
			sum = 0;	
			i--;
		}
	}
	if(ans > m) return true;//>m说明mid太小
	return false;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
	
	cin >> n >> m;
	int lb = 0,ub = 0;
	for (int i = 0; i < n; i += 1){
		cin >> x[i];
		lb = max(lb,x[i]);
		ub = ub+x[i];
	}
	while (ub>lb){
		int mid = (ub+lb)/2;
		if(mid == lb && C(mid)) {
			printf("%d\n",ub);return 0;
		}
		if(C(mid)) lb = mid;
		else ub = mid;
	}
	printf("%d\n",lb);
	return 0;
}

ps:给出一个poj能ac但是有误的代码:

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <bitset>
#include <list>
#include <sstream>
#include <set>
#include <functional>
using namespace std;

#define INF 0x3f3f3f3f
#define MAX 100
typedef long long ll;
int n,m;
int x[100005];

bool C(int d)
{
	int sum = 0,ans = 1;
	for (int i = 0; i < n; i += 1){
		sum += x[i];
		if(sum > d){
			ans++;
			sum = x[i];	
		}
	}
	if(ans > m) return true;
	return false;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
	
	cin >> n >> m;
	int lb = 0,ub = 0;
	for (int i = 0; i < n; i += 1){
		cin >> x[i];
		lb = max(lb,x[i]);
		ub = ub+x[i];
	}
	while (ub>lb){
		int mid = (ub+lb)/2;
		if(C(mid)) lb = mid+1;
		else ub = mid-1;
	}
	printf("%d\n",ub);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值