解决问题(DP)


问题8-3

对就业没有兴趣的郑来没有意识到提升实力的必要性,一直逃避解决问题。但是听了aa的培训之后,郑来有了一个梦想,就是进入aa工作!

郑来为了进入aa,需要按顺序准确地解出P(1 ≤ P ≤ 300)问题才可以。但是由于疏于解题已经很长时间,郑来靠自己一道问题都解不出来。因此郑来请了每天都努力解题的昌洙来帮忙。之前昌洙的实力和郑来差不多,但是经过每天努力的练习,现在昌洙不论接到了怎样的问题,数量多么多的问题,都可以把接到的全部问题准确地在一个月内解出来。

努力练习的昌洙向郑来提出了需要报酬。还好,平时每个月郑来都会从父母那里得到M(1 ≤ M ≤  1000)元的零用钱。但是不幸的是,郑来收到问题的那个月已经把零用钱都用完了。

昌洙说,各个问题的难易度都不一样,因此对第i个问题,在收到该问题那天收取A_i(1≤ A_i ≤ M)元,委托了问题的下一个月(问题解决后)收取B_i(1 ≤ B_i ≤ M)元。

另外,梦想成为时尚达人的郑来在每月末都将剩下的所有零花钱用在网上购物上。

郑来开始好奇自己收到的问题要花多长时间能解决完。请求出郑来解决所有问题所需要的最小月数。

 

输入

第一行输入给出空格分隔的两个自然数MP

从第二行开始到p+1行中输入给出两个自然数A_i B_i,用空格分开。

i个问题只能在第i-1个问题解决后才能委托。

输出

输出解决郑来委托的所有问题的最小月数。

 

案例输入

100 5

40 20

60 20

30 50

30 50

40 40

案例输出

6

提示

+------+-------+--------+---------+---------+--------+

|     | Avail |Probs | Before | After | Clothes|

|Month | Money | Solved | Payment | Payment | Money |

+------+-------+--------+---------+---------+--------+

1  | 0   | -none- |   0   |   0   |    0 |

2  | 100  | 1, 2 | 40+60  |   0   |    0 |

3  | 100  | 3, 4 | 30+30  | 20+20 |    0 |

4  | 100  | -none- |   0   |  50+50 |    0 |

5  | 100  |  5   |  40   |   0   |   60 |

6  | 100  | -none- |   0   |  40   |   60 |

+------+-------+--------+---------+---------+--------+

100 3)(20 50)(20 40)(20 20

+------+-------+--------+---------+---------+--------+

|     | Avail |Probs | Before | After | Clothes|

|Month | Money | Solved | Payment | Payment | Money |

+------+-------+--------+---------+---------+--------+

1  | 0   | -none- |   0   |   0   |    0 |

2  | 100  | 1    | 20     |   0   |    0 |

3  | 100  | 2, 3 | 20+20  | 50    |    0 |

4  | 100  | -none- |   0   |  40+20 |    0 |

+------+-------+--------+---------+---------+--------+

 

#include<cstdio>

int tot_before[301], tot_after[301];
int m,p;
int d[602][301];

int main(){
	scanf("%d%d", &m, &p);
	tot_before[0] = 0;
	tot_after[0] = 0;
	int bef, aft;
	for (int i = 1; i <= p; i++){
		scanf("%d%d", &bef, &aft);
		tot_before[i] = tot_before[i - 1] + bef;
		tot_after[i] = tot_after[i - 1] + aft;
	}
	// first month, no problem solved,
	d[0][0] = 0;
	for (int i = 1; i <=p; i++) d[0][i] = -1;

	int minleft = -1;
	// i=every month
	for (int i = 1; i <= 2 * p; i++){
		// j= every problem this month
		for (int j = 1; j <= p; j++){
			minleft = -1;
			// k=solved problem last month
			for (int k = 0; k <= j; k++){
				if (d[i - 1][k] != -1 // exists debt last month
					&& (d[i - 1][k] + (tot_before[j] - tot_before[k])) <= m //last debt plus this month new
					&& (tot_after[j] - tot_after[k]) <= m) // left to next month
				{
					if (minleft == -1 // debt is not initlized
						|| minleft > (tot_after[j] - tot_after[k])) // debt is not minimum
						minleft = tot_after[j] - tot_after[k]; // update it
				}
			}
			// i month, solved j problem, how much debt was left to next month.
			// and it is minimum..
			d[i][j] = minleft;
		}
	}
	// find which month the last problem P is solved,print it.
	for (int i = 1; i <= 2 * p; i++){
		if (d[i][p] != -1){
			// why add 2?, first and last month are not included
			printf("%d\n", i + 2);
			break;
		}
	}
	
	return 0;
}

 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值