碎碎念:因为这是隔壁lqy班的oj题目,为了白嫖算法题 ,我就用朋友的账号帮他做。然后发现,两个班题目难度差异挺大的,我们是比较基础的题,隔壁班这个偏向于应用,题意不好理解、思路也不是单一的动态规划(比如第一题并不具有无后效性,第二题还要结合DFS…)总之,多刷算法题是没错的。
很巧的是,刚好在做题的时候一位电气学院的老朋友来问我计院算法学习的难度如何,我就顺手把作业截了几张图给他。我记得他高中学信息学奥赛的大佬,果不其然,他觉得这种题很基础…嗯…
知识: 一般来说,能够采用动态规划方法求解的问题必须满足.最优化原理和无后效性原则
最优化原理:子问题的局部最优将导致整个问题的全局最优,即问题具有最优子结构的性质,也就是说一个问题的最优解只取决于其子问题的最优解,非最优解对问题的求解没有影响
无后效性原则:未来发生的事情对于过去没有影响,当前的状态是此前历史的一个完整总结,此前的历史只能通过当前的状态去影响过程未来的演变。
Problem A. 晴天小猪历险记之Hill
时间限制 1000 ms
内存限制 128 MB
题目描述
这一天,他来到了一座深山的山脚下,因为只有这座深山中的一位隐者才知道这种药草的所在。但是上山的路错综复杂,由于小小猪的病情,晴天小猪想找一条需时最少的路到达山顶,但现在它一头雾水,所以向你求助。
山用一个三角形表示,从山顶依次向下有1段、2段、3段等山路,每一段用一个数字T(1< =T< =100)表示,代表晴天小猪在这一段山路上需要爬的时间,每一次它都可以朝左、右、左上、右上四个方向走(注意:在任意一层的第一段也可以走到本层的最后一段或上一层的最后一段)。
晴天小猪从山的左下角出发,目的地为山顶,即隐者的小屋。
输入数据
第一行有一个数 n (2≤n≤1000), 表示山的高度。
从第二行至第 n+1 行,第 i+1 行有 i 个数,每个数表示晴天小猪在这一段山路上需要爬的时间。
输出数据
一个数,即晴天小猪所需要的最短时间。
样例输入
5
1
2 3
4 5 6
10 1 7 8
1 1 4 5 6
样例输出
10
样例说明
在山的两侧的走法略有特殊,请自己模拟一下,开始我自己都弄错了……
Problem B. 清帝之惑之顺治
时间限制 1000 ms
内存限制 128 MB
题目描述
顺治喜欢滑雪,这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待太监们来载你。顺治想知道载一个区域中最长的滑坡。
区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
顺治可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-…-3-2-1更长。事实上,这是最长的一条。
输入数据
输入的第一行表示区域的行数 R 和列数 C (1≤R,C≤500) 。下面是 R 行,每行有 C 个整数,代表高度 h,0≤h<103 。
输出数据
输出最长区域的长度。
样例输入
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
样例输出
25
分析:一开始真没看出来和动态规划啥关系hhh.想着用深度优先搜索的方式暴力解出,后来一想这个规模量,天哪还是放弃吧(肯定runtime error了)。于是想到动态规划,怎么想到的呢,这章主题就是动态规划,所以就这样啦。
DFS函数用来进行深度优先搜索,搜索到底就返回此处的最大坡度,如果某处存储的dp!=1,说明已经被遍历过,根据动态规划的原理,看作是最优解,也就是最大坡度,然后直接return回来。
核心代码就是:
dp[i][j]=max(dp[i][j-1],dp[i][j+1],dp[i-1][j],dp[i+1[j])+1
其中的dp[
i
∗
i^*
i∗][
j
∗
j^*
j∗]是由DFS得到的。
最后再来解答为什么可以使用动态规划,在最前面我们提到,常规的动态规划必然具有无后效性——后来发生的事情对于已经确定的历史没有影响。事实确实是这样。我们DFS到了某个位置的尽头,出现了四面楚歌(四周都比他大)的境地,那么这个地方必然有取到最优解1;然后递归上来,下一个值也可以确定最优解:这个值的子问题的子问题的…必然也可以DFS到底,收上来就能找到答案。
深入思考还是很费脑子的。
#include<iostream>
#include<cmath>
using namespace std;
int r, c;
int a[501][501];
int dp[501][501];//dp存储的是目前位置最高的坡度(是的,假设存储的就是最高的,再动态地调整!)
int DFS(int x, int y) {//深度优先:找到该位置处的最大
if (dp[x][y] > 1) { //如果dp有值,说明被访问过,根据动态规划原理,设定它为最优值
return dp[x][y];
}
else if (x -1 >=0 && a[x][y] > a[x - 1][y] ) {//上
dp[x][y] = max(dp[x][y],DFS(x-1,y)+1); //注意:这里要加1,因为踩在小矮子的身上的
}
if (y >= 1 && a[x][y] > a[x][y - 1]) {//左
dp[x][y] = max(dp[x][y], DFS(x, y-1)+1);
}
if (y+1 < c && a[x][y] > a[x][y + 1]) {//右
dp[x][y] = max(dp[x][y], DFS(x, y + 1)+1);
}
if (x + 1 < r && a[x][y] > a[x+1][y ]) {//下
dp[x][y] = max(dp[x][y], DFS(x+1, y)+1);
}
return dp[x][y];//这个地方,返回的就是最大值
}
int main() {
cin >> r >> c;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
cin >> a[i][j];
dp[i][j] = 1;//初始化为1,顺治皇帝不滑站在那儿就是1
}
}
//开始动态规划
int ans = 0;
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
dp[i][j] =DFS(i, j);
ans = max(ans,dp[i][j]);
}
}
cout << ans;
}
Problem C. 积木城堡
时间限制 1000 ms
内存限制 128 MB
题目描述
XC的儿子小XC最喜欢玩的游戏用积木垒漂亮的城堡。城堡是用一些立方体的积木垒成的,城堡的每一层是一块积木。小XC是一个比他爸爸XC还聪明的孩子,他发现垒城堡的时候,如果下面的积木比上面的积木大,那么城堡便不容易倒。所以他在垒城堡的时候总是遵循这样的规则。
小XC想把自己垒的城堡送给幼儿园里漂亮的女孩子们,这样可以增加他的好感度。为了公平起见,他决定把送给每个女孩子一样高的城堡,这样可以避免女孩子们为了获得更漂亮的城堡而引起争执。可是他发现自己在垒城堡的时候并没有预先考虑到这一点。所以他现在要改造城堡。由于他没有多余的积木了,他灵机一动,想出了一个巧妙的改造方案。他决定从每一个城堡中挪去一些积木,使得最终每座城堡都一样高。为了使他的城堡更雄伟,他觉得应该使最后的城堡都尽可能的高。
任务:
请你帮助小XC编一个程序,根据他垒的所有城堡的信息,决定应该移去哪些积木才能获得最佳的效果。
输入数据
第一行是一个整数 N (N≤100), 表示一共有几座城堡。以下 N 行每行是一系列非负整数,用一个空格分隔,按从下往上的顺序依次给出一座城堡中所有积木的棱长。用-1结束。一座城堡中的积木不超过100块,每块积木的棱长不超过100。
输出数据
一个整数,表示最后城堡的最大可能的高度。如果找不到合适的方案,则输出 0 。
样例输入
2
2 1 –1
3 2 1 –1
样例输出
3
样例说明
原数据有误,不知我修正后是不是对?
Problem C. 积木城堡
时间限制 1000 ms
内存限制 128 MB
题目描述
XC的儿子小XC最喜欢玩的游戏用积木垒漂亮的城堡。城堡是用一些立方体的积木垒成的,城堡的每一层是一块积木。小XC是一个比他爸爸XC还聪明的孩子,他发现垒城堡的时候,如果下面的积木比上面的积木大,那么城堡便不容易倒。所以他在垒城堡的时候总是遵循这样的规则。
小XC想把自己垒的城堡送给幼儿园里漂亮的女孩子们,这样可以增加他的好感度。为了公平起见,他决定把送给每个女孩子一样高的城堡,这样可以避免女孩子们为了获得更漂亮的城堡而引起争执。可是他发现自己在垒城堡的时候并没有预先考虑到这一点。所以他现在要改造城堡。由于他没有多余的积木了,他灵机一动,想出了一个巧妙的改造方案。他决定从每一个城堡中挪去一些积木,使得最终每座城堡都一样高。为了使他的城堡更雄伟,他觉得应该使最后的城堡都尽可能的高。
任务:
请你帮助小XC编一个程序,根据他垒的所有城堡的信息,决定应该移去哪些积木才能获得最佳的效果。
输入数据
第一行是一个整数 N (N≤100), 表示一共有几座城堡。以下 N 行每行是一系列非负整数,用一个空格分隔,按从下往上的顺序依次给出一座城堡中所有积木的棱长。用-1结束。一座城堡中的积木不超过100块,每块积木的棱长不超过100。
输出数据
一个整数,表示最后城堡的最大可能的高度。如果找不到合适的方案,则输出 0 。
样例输入
2
2 1 –1
3 2 1 –1
样例输出
3
样例说明
原数据有误,不知我修正后是不是对?
快速幂+快速矩阵乘(这个写的太绝了)
long c=10000007;
public long divide(long a, long b) {
if (b == 0)
return 1;
else if (b % 2 == 0) //偶数情况
return divide((a % c) * (a % c), b / 2) % c;
else//奇数情况
return a % c * divide((a % c) * (a % c), (b - 1) / 2) % c;
}