4.15 每周作业 —— 简单DP
免费馅饼
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 102 Accepted Submission(s) : 35
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
<center> </center>
为了使问题简化,假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)
Input
Output
提示:本题的输入数据量比较大,建议用scanf读入,用cin可能会超时。
Sample Input
6 5 1 4 1 6 1 7 2 7 2 8 3 0
Sample Output
4
思路: 简单DP,按照DP的思考步骤。
一.找到最优子问题
那么我们的问题就是 “左 中 右”的选择
二.找到决策,也就是会影响到结果的因素
那么这个问题会影响到结果的就是 时间和地点
三.提出状态
由第二点可以知道,影响到结果的有两个因素,所以状态应该是二维的
DP[i][j]==在 i秒 的时候 在 j点 的馅饼数
四.提出状态转移方程
考虑到边界问题,如果我们在第 0 点 或者 第 10 点,那我们的选择就只有 “在原地”或者 “旁边的一个”,这样就只有两个选择,所以需要特判一下
if(j<=0){ j=0; dp[i][j]=max(dp[i-1][j],dp[i-1][j+1])+cake[i][j]; } else if(j==10){ dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+cake[i][j]; } else{ dp[i][j]=max_judge(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1])+cake[i][j];//比较一下第i秒的j号位置,是上一秒的j的左边,还是上一秒的j的右边,还是上一秒的j最多 }
其实我们可以看到,我们每次要考虑到的只有上一秒的情况,所以其实可以用滚动数组来节省空间,不过我懒得写了,不会的话参考01背包的滚动数组情况。
下面给出麻烦代码
//#pragma comment(linker,"/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<cstring> #include<string> #include<cstdio> #include<vector> #include<set> #include<map> using namespace std; int n; int T,x; int loc; int Max; int sum_time; int cake[100005][15]; int dp[100005][15]; int max_judge(int a,int b,int c) { int ans; ans=a>b?a:b; ans=ans>c?ans:c; return ans; } int main() { while(cin>>n && n) { loc=5; Max=0; sum_time=0; memset(dp,0,sizeof(dp)); memset(cake,0,sizeof(cake)); for(int i=1;i<=n;i++){ scanf("%d%d",&x,&T); sum_time=max(T,sum_time); cake[T][x]++; } for(int i=1;i<=sum_time;i++){ for(int j=loc-i;j<=10 && j<=loc+i;j++){ if(j<=0){ j=0; dp[i][j]=max(dp[i-1][j],dp[i-1][j+1])+cake[i][j]; } else if(j==10){ dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+cake[i][j]; } else{ dp[i][j]=max_judge(dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1])+cake[i][j]; } } } for(int i=0;i<=10;i++){ Max=max(dp[sum_time][i],Max); } cout<<Max<<endl; } return 0; }
搬寝室
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 63 Accepted Submission(s) : 23
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
Input
Output
Sample Input
2 1 1 3
Sample Output
4
Author
Source
思路:这题一开始感觉是简单排序,然后就WA了,后面想想不行 比如 1 99 100 这样的数据,简单排序选择的话 就会选择1 和99 ,但实际上是 99 和 100.
还是得靠DP来解决。
正式开始
首先,我们先sort排序下。 这样,我们知道,两个数的差最小的话,肯定是排序后的左边一个和右边一个,这样我们的问题就变成了选左边或者右边。
下面按照DP的简单思路:
一.找出最小子问题
我们的问题就是选出相差值最小的一对,那么我们面对的问题就 我们要拿的这一对中 包不包含现在面对的这个 东西
二.找到决策,也就是影响到结果的因素
那么我们可以知道,影响到问题的决策 也就是 物品 和 对数
三.提出状态
由二我们可以知道影响到问题的决策有两个 也就是 状态也就是 二维的
DP[i][j]==在面对第 i 个 物品时,拿了 j 对 物品的疲劳值
四.提出转移方程
dp[i][j] = Min_(dp[i - 2][j - 1] +sum(wei[i],wei[i-1]),dp[i - 1][j]); //比较下 是拿 这一个加前一个 这一对 加上前面的对数 的疲劳值 和 不拿这一个 的 对数 的疲劳值
下面给出AC程序:
可能还是有人比较模糊,那就再解释下。
我们从最小的状态开始,也就是
比如只有 a b两件,那么我们只能拿这两个
但是如果有 a b c 三件,首先我们知道 c-a 肯定是大于 c-b的,所以不需要考虑
所以我们要考虑的是要不要拿c,如果拿c的话,那么我们肯定是要拿b的,如果不拿c的话,那么我们就是拿a 和 b了
#include<iostream> #include<algorithm> #include<cstring> using namespace std; #define M 2005 typedef int ll; ll n, k; ll limit_i; ll limit_k; ll wei[M]; ll dp[M][M]; void init() { memset(dp, 0x3f3f3f3f, sizeof(dp)); for (int i = 0; i <= n; i++) { dp[i][0] = dp[0][i] = 0; } } ll Min_(ll a, ll b) { return a < b ? a : b; } ll sum(ll a, ll b) { return (a - b)*(a - b); } int main() { while (cin>>n>>k) { init(); for (int i = 1; i <= n; i++) { scanf("%d", &wei[i]); } sort(wei + 1, wei + n + 1); for (int i = 2; i <= n; i++) { limit_i = (i >>1); for (int j = 1; j <= limit_i && j <= k; j++) { dp[i][j] = Min_(dp[i - 2][j - 1] +sum(wei[i],wei[i-1]),dp[i - 1][j]); } } cout << dp[n][k] << endl; } return 0; }
Humble Numbers
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 12 Accepted Submission(s) : 9
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
Write a program to find and print the nth element in this sequence
Input
Output
Sample Input
1 2 3 4 11 12 13 21 22 23 100 1000 5842 0
Sample Output
The 1st humble number is 1. The 2nd humble number is 2. The 3rd humble number is 3. The 4th humble number is 4. The 11th humble number is 12. The 12th humble number is 14. The 13th humble number is 15. The 21st humble number is 28. The 22nd humble number is 30. The 23rd humble number is 32. The 100th humble number is 450. The 1000th humble number is 385875. The 5842nd humble number is 2000000000.
Source
//#pragma comment(linker,"/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<iterator> #include<cstdio> #include<cstring> #include<string> #include<stack> #include<list> #include<set> #include<deque> #include<utility> #include<ctime> using namespace std; typedef long long ll; ll t; ll temp; ll n[] = { 2,3,5,7 }; ll ans[6000]; set<ll>num; string str[10]; void init() { num.insert(1), num.insert(0); register set<ll>::iterator iter = num.begin(); for (int i = 1; i <= 4900; i++) { iter++; for (int j = 0; j < 4; j++) { temp = (*iter)*n[j]; num.insert(temp); } } iter = num.begin(); for (int i = 0; i <= 5842; i++) { ans[i] = *iter; iter++; } str[0] = "th", str[1] = "st", str[2] = "nd", str[3] = "rd"; for (int i = 4; i <= 9; i++) { str[i] = "th"; } } int main() { init(); while (cin>>t && t) { cout << "The " << t; if (t%100 == 11 || t % 100 == 12 || t % 100 == 13) { cout << str[0]; } else { cout << str[t % 10]; } cout << " humble number is " << ans[t] << '.' << endl; } return 0; }
Super Jumping! Jumping! Jumping!
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 44 Accepted Submission(s) : 27
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
<center> </center>
The game can be played by two or more than two players. It consists of a chessboard(棋盘)and some chessmen(棋子), and all chessmen are marked by a positive integer or “start” or “end”. The player starts from start-point and must jumps into end-point finally. In the course of jumping, the player will visit the chessmen in the path, but everyone must jumps from one chessman to another absolutely bigger (you can assume start-point is a minimum and end-point is a maximum.). And all players cannot go backwards. One jumping can go from a chessman to next, also can go across many chessmen, and even you can straightly get to end-point from start-point. Of course you get zero point in this situation. A player is a winner if and only if he can get a bigger score according to his jumping solution. Note that your score comes from the sum of value on the chessmen in you jumping path.
Your task is to output the maximum value according to the given chessmen list.
Input
N value_1 value_2 …value_N
It is guarantied that N is not more than 1000 and all value_i are in the range of 32-int.
A test case starting with 0 terminates the input and this test case is not to be processed.
Output
Sample Input
3 1 3 2 4 1 2 3 4 4 3 3 2 1 0
Sample Output
4 10 3
Author
if (num[j] < num[i]) { dp[i] = max(dp[i], dp[j] + num[i]); }//比较一下,如果以i点为结尾的话,会不会更大
下面给出AC方程:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<stack> #include<list> #include<deque> #include<utility> using namespace std; #define M 1005 int n; int ans; int dp[M]; int num[M]; void init() { ans = 0; for (int i = 1; i <= n; i++) { dp[i] = num[i]; } } int main() { while (cin>>n && n) { for (int i = 1; i <= n; i++) { cin >> num[i]; } init(); for (int i = 1; i <= n; i++) { for (int j = 1; j <= i; j++) { if (num[j] < num[i]) { dp[i] = max(dp[i], dp[j] + num[i]); } } ans = max(ans, dp[i]); } cout << ans << endl; } return 0; }
龟兔赛跑
Time Limit : 1000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 18 Accepted Submission(s) : 8
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
最近正值HDU举办50周年校庆,社会各大名流齐聚下沙,兔子也趁此机会向乌龟发起挑战。虽然乌龟深知获胜希望不大,不过迫于舆论压力,只能接受挑战。
比赛是设在一条笔直的道路上,长度为L米,规则很简单,谁先到达终点谁就算获胜。
无奈乌龟自从上次获胜以后,成了名龟,被一些八卦杂志称为“动物界的刘翔”,广告不断,手头也有了不少积蓄。为了能够再赢兔子,乌龟不惜花下血本买了最先进的武器——“"小飞鸽"牌电动车。这辆车在有电的情况下能够以VT1 m/s的速度“飞驰”,可惜电池容量有限,每次充满电最多只能行驶C米的距离,以后就只能用脚来蹬了,乌龟用脚蹬时的速度为VT2 m/s。更过分的是,乌龟竟然在跑道上修建了很多很多(N个)的供电站,供自己给电动车充电。其中,每次充电需要花费T秒钟的时间。当然,乌龟经过一个充电站的时候可以选择去或不去充电。
比赛马上开始了,兔子和带着充满电的电动车的乌龟并列站在起跑线上。你的任务就是写个程序,判断乌龟用最佳的方案进军时,能不能赢了一直以恒定速度奔跑的兔子。
Input
第一行是一个整数L代表跑道的总长度
第二行包含三个整数N,C,T,分别表示充电站的个数,电动车冲满电以后能行驶的距离以及每次充电所需要的时间
第三行也是三个整数VR,VT1,VT2,分别表示兔子跑步的速度,乌龟开电动车的速度,乌龟脚蹬电动车的速度
第四行包含了N(N<=100)个整数p1,p2...pn,分别表示各个充电站离跑道起点的距离,其中0<p1<p2<...<pn<L
其中每个数都在32位整型范围之内。
Output
题目数据保证不会出现乌龟和兔子同时到达的情况。
Sample Input
100 3 20 5 5 8 2 10 40 60 100 3 60 5 5 8 2 10 40 60
Sample Output
Good job,rabbit! What a pity rabbit!
Author
Source
dp[i] = min(dp[i], dp[j] + sum(i, j));//sum计算的是从j到i花费的时间
下面是AC方程:
//#pragma comment(linker,"/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<string> #include<stack> #include<list> #include<deque> #include<utility> using namespace std; #define M 105 #define inf 0x3f3f3f3f typedef double i_d; int L; i_d r_time; int st, ed; i_d N, C, T; i_d VR, VT1, VT2; i_d dp[105]; int num[105]; void init() { r_time = L / VR; ed = 0, st = N + 1; num[ed] = 0, num[st] = L; for (int i = 1; i <= st; i++) { dp[i] = inf; } dp[0] = 0; } void get_data() { cin >> N >> C >> T; cin >> VR >> VT1 >> VT2; for (int i = 1; i <= N; i++) { cin >> num[i]; } } i_d sum(int a, int b) { i_d dis, time; dis = num[a] - num[b]; if (dis <= C) { time=dis / VT1; } else { time = C / VT1 + (dis - C) / VT2; } return b == 0 ? time : time + T;//记住如果j站为0的话那么就是起点,起点不需要充电,也就不需要花费T时间 } int main() { while (cin>>L) { get_data(); init(); for (int i = 1; i <= st; i++) { for (int j = 0; j < i; j++) { dp[i] = min(dp[i], dp[j] + sum(i, j)); } } if (r_time < dp[st]) { cout << "Good job,rabbit!" << endl; } else { cout << "What a pity rabbit!" << endl; } } return 0; }
FatMouse's Speed
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 12 Accepted Submission(s) : 5
Special Judge
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
Input
The data for a particular mouse will consist of a pair of integers: the first representing its size in grams and the second representing its speed in centimeters per second. Both integers are between 1 and 10000. The data in each test case will contain information for at most 1000 mice.
Two mice may have the same weight, the same speed, or even the same weight and speed.
Output
W[m[1]] < W[m[2]] < ... < W[m[n]]
and
S[m[1]] > S[m[2]] > ... > S[m[n]]
In order for the answer to be correct, n should be as large as possible.
All inequalities are strict: weights must be strictly increasing, and speeds must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one.
Sample Input
6008 1300 6000 2100 500 2000 1000 4000 1100 3000 6000 2000 8000 1400 6000 1200 2000 1900
Sample Output
4 4 5 9 7
Source
//#pragma comment(linker,"/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<iterator> #include<cstdio> #include<cstring> #include<string> #include<stack> #include<list> #include<set> #include<queue> #include<deque> #include<utility> #include<ctime> using namespace std; #define M 1005 #define inf 0x3f3f3f3f struct Data { int id; int wei; int speed; bool operator<(Data &x){ return wei < x.wei; } }Mouse[M]; int dp[M]; int ans[M]; int n, len, tail; int id, wei, speed; void get_data() { id = 1; while (cin>>wei>>speed) { //if (wei == 0) { break; } Mouse[id].id = id; Mouse[id].wei = wei; Mouse[id++].speed = speed; } Mouse[0].wei = inf, Mouse[0].speed = -inf; n = id - 1; } void dfs(int T) { if (!T) { return; } dfs(ans[T]); cout << Mouse[T].id << endl; } int main() { get_data(); sort(Mouse + 1, Mouse + n + 1); for (int i = 1; i <= n; i++) { dp[i] = 1; for (int j = 1; j < i; j++) { if (Mouse[i].wei > Mouse[j].wei && Mouse[i].speed < Mouse[j].speed && dp[i] < dp[j] + 1) { dp[i] = dp[j] + 1; ans[i] = j; } } if (len < dp[i]) { len = dp[i]; tail = i; } } cout << len << endl; dfs(tail); return 0; }
Common Subsequence
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 12 Accepted Submission(s) : 6
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
The program input is from a text file. Each data set in the file contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
Sample Input
abcfbc abfcab programming contest abcd mnp
Sample Output
4 2 0
Source
//#pragma comment(linker,"/STACK:1024000000,1024000000") #include<iostream> #include<algorithm> #include<iterator> #include<cstdio> #include<cstring> #include<string> #include<stack> #include<list> #include<set> #include<deque> #include<utility> #include<ctime> using namespace std; #define M 1005 int a_len; int b_len; int dp[M][M]; char a[M], b[M]; void init() { a_len = strlen(a + 1), b_len = strlen(b + 1); for (int i = 0; i <= a_len; i++) { for (int j = 0; j <= b_len; j++) { dp[i][j] = 0; } } } int main() { while (scanf("%s%s",a+1,b+1)!=EOF) { init(); for (int i = 1; i <= a_len; i++) { for (int j = 1; j <= b_len; j++) { if (a[i] == b[j]) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = max(dp[i - 1][j], dp[i][j-1]); } } } cout << dp[a_len][b_len] << endl; } return 0; }