POJ 3265 Problem Solving--线性dp

60 篇文章 0 订阅
1 篇文章 0 订阅

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; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值