In easier times, Farmer John’s cows had no problems. These days, though, they have problems, lots of problems; they have P (1 ≤ P ≤ 300) problems, to be exact. They have quit providing milk and have taken regular jobs like all other good citizens. In fact, on a normal month they make M (1 ≤ M ≤ 1000) money.
Their problems, however, are so complex they must hire consultants to solve them. Consultants are not free, but they are competent: consultants can solve any problem in a single month. Each consultant demands two payments: one in advance (1 ≤ payment ≤ M) to be paid at the start of the month problem-solving is commenced and one more payment at the start of the month after the problem is solved (1 ≤ payment ≤ M). Thus, each month the cows can spend the money earned during the previous month to pay for consultants. Cows are spendthrifts: they can never save any money from month-to-month; money not used is wasted on cow candy.
Since the problems to be solved depend on each other, they must be solved mostly in order. For example, problem 3 must be solved before problem 4 or during the same month as problem 4.
Determine the number of months it takes to solve all of the cows’ problems and pay for the solutions.
Input:
Line 1: Two space-separated integers: M and P.
Lines 2…P+1: Line i+1 describes problem i with two space-separated integers: Bi and Ai. Bi is the payment to the consult before the problem is solved; Ai is the payment to the consult after the problem is solved.
Output:
Line 1: The number of months it takes to solve and pay for all the cows’ problems.
题目大意:
给出每个月m的经费(m在每个月会刷新并且多余的钱不会留到下一个月)和p个问题。
接下来p行,每行一个首款ai和尾款bi,尾款用于下一个月付款,也就是说每个月的ai要能和上个月的bi一起给完。
问题需要按顺序解决,问题ai必须在问题ai+1之前解决或在问题ai+1的同一个月内解决。
求解决所有问题p的最小月数。
解题思路:
m要在第二个月才可以用,我们可以看作第一个月就有m的经费,最后结果为dp[m]+1,1代表等m的第一月。
dp公式:dp[i]=min(dp[i],dp[j]+z),z为解决j问题的最小月数。
需要注意的是,如果dp[j]+z=dp[i]时,我们需要尽量让前j个月的尾款b1-j尽量多。
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
const int INF=0x3f3f3f3f;
int dp[305],lm[305],a[305],b[305],n,m,z,x,y;
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=1;i<=m;i++)cin>>a[i]>>b[i];
memset(lm,0,sizeof(lm));
dp[0]=1;
for(int i=1;i<=m;i++)//1-m个为题的最优解(最少月数)
{
dp[i]=INF,x=a[i],y=b[i];
for(int j=i-1;j>=0&&x<=n&&y<=n;j--)//通过前i个推导i的最优解
{
z=dp[j]+2-(lm[j]<=n-x);//是否能支付当月和上月尾款,否则两个月付清
//默认是dp[j]+2个月付清金额,如果lm[j]<=n-x也多余的钱就是可以把上个月尾款付清那就减少一个月
if(z<dp[i]||(z==dp[i]&&lm[i]>y))//更新最小时间,以及最小时间下能累计多的尾款
{
dp[i]=z;
lm[i]=y;
}
x+=a[j];//对前j个月的首款累加求更小的月数
y+=b[j];//对前j个月的尾款累加求更小的月数
// for(int k=0;k<=m;k++)printf("%d ",dp[k]);for(int k=0;k<=m;k++)printf("%3d ",lm[k]);printf("%4d%4d%4d\n",x,y,z);
}
}
cout<<dp[m]+1<<endl;
}
return 0;
}