题目大意:FJ有n天,每天的金钱花费为moneyi (每天不一定相同),给定一个m,代表FJ想要创建的周期个数,每个周期包括一天或者连续几天,要求我们计算出最小的周期金钱,这个数大于或等于任何一个周期金钱的和。
题目链接:http://poj.org/problem?id=3273
方法:二分法
思路:二分地量就不说了,都懂得,关键在于判定,可以通过你模拟的值(即二分时的量)来进行周期划分,看满足你模拟的值最少周期数是多少,如果大于
m,显然是不满足的,如果小于,那么划分m组是绰绰有余的,等于就不用说了。。重要的是注意确定一个分段点后,起点在哪儿,是最后一个满足的数?还是接下来这个不满足的数?而且要注意比较一天的情况,因为一天也可能是一个周期。代码有详细的标注。
算法实现:
#include<stdio.h>
#define MAX 100003
int main()
{
int N,M;
int low,high,mid;
int i,res,mon,sum,days,a[MAX];//res记录合适的周期金钱,mon记录分了多少个周期,sum记录连续几天的金钱和,days记录连续几天是可行的,mon记录间断点。
while(scanf("%d%d",&N,&M)!=EOF)
{
high=0;
for(i=0;i<N;i++)
{
scanf("%d",&a[i]);
high+=a[i];
}
low=0;
while(high-low>=0)
{
sum=0;
mon=0;
days=0;
mid=(high+low)/2;
for(i=0;i<N;i++)
{
if(a[i]+sum>mid)
{
sum=0;
if(days>=1)//days是用来分别几天和0天的情况,即是否存在至少一天满足要求。
{
i--;//当出现间断点时,即此时间断点在i和i-1之间,a[i]是不符合要求的,所以下一轮要作为起点,所以i--.
days=0;//且days要清0.
mon++;//间断点加一。
}
else
{
mon=-1;//如果只一天得金钱都不符合,则赋值-1,并跳出。
break;
}
}
else//如果仍满足,sum则累加,连续的天数加一。
{
sum+=a[i];
days++;
}
if(mon==-1)//如果有一天的金钱比mid大,则退出,不需在循环。
break;
}
if(mon==-1)
{
low=mid+1;
continue;
}
if(mon+1>M)//因为mon是间断点,所以是将整个天数分为mon+1块。
low=mid+1;
else
{
high=mid-1;
res=mid;//符合则记录。
}
}
printf("%d\n",res);
}
return 0;
}