杭电2955
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2955
题目大意是:一个抢银行的人,想在尽可能低的被抓概率内偷到更多的钱。
输入:
第一行:p和num,分别表示可忍受的被抓概率和银行的个数。
接下来num行,每行有w和v,分别表示该银行的钱数和被抓概率
输出:
在被抓概率小于p的情况下,最大的抢的金额数。
思路:
动态规划,类似于背包问题,但是如何定义数组有所区别,也就是状态转移方程,因为概率是要相乘的,而不是相加。
换一种想法,最小被抓概率,也就是逃跑概率要超过p,所以在输入的时候将概率都用1减去,就可以在后续直接相乘了。
状态转移方程为
dp[j]=max(dp[j],dp[j−s[i].m]∗s[i].p)
意思是偷 j 金额的钱,逃跑概率为dp[j]
杭电1506
题目链接 (http://acm.hdu.edu.cn/showproblem.php?pid=1506)
大致题意是:
有很多矩形,放在同一水平线上,宽都是1,高不同,求该区域下连通的最大矩形面积。
思路:最大的矩形面积,就是要遍历每个矩形,找出每个矩形往左数和往右数比它矮的第一个,两者距离乘以高,就是面积。对这i个面积,找出最大值来,即为所求。
但是一个个计算肯定超时,然后我们想到动态规划的思路:
针对第i个矩形,如果第i-1个比它高,那L[i]至少等于L[i-1]。但是L[i-1]只是比i-1矮的,不一定比第i个矩形矮,所以还要再找第L[ L[i-1]-1 ],看这个矩形是否比第i个矮,一直循环。这样,从左往右,可以一个个记录下来,降低了复杂度。
右边的也一样,只是从右往左记录。
所以两个for循环,分别计算L[i]和R[i]。还有一个for循环,找最大值。代码如下:
#include <iostream>
#include <algorithm>
using namespace std;
int l[100010], r[100010];//分别记录往左和往右的位置
long long h[100010];
//l[i]表示第i个矩形往左数,比它矮的第一个矩形的位置,r[i]也是
int main()
{
int n;
while (true)
{
cin >> n;
if (n == 0) break;
for (int i = 0; i < n; i++)
cin >> h[i];
for (int i = 0; i < n; i++)
{
l[i] = i;
r[i] = i;
}
for (int i = 1; i < n; i++)
{ //这里要注意,要while循环,必须一直迭代者往前搜索
//如果i前边那个比i高,那么l[i]至少等于l[i-1],还需要看l[i-1]前边那个是否比i高
while (l[i]-1>=0 && h[l[i] - 1] >= h[i])
{
l[i] = l[l[i] - 1];
}
}
for (int i = n - 2; i >= 0; i--)
{
while (r[i] + 1<n && h[r[i] + 1] >= h[i])
{
r[i] = r[r[i] + 1];
}
}
long long sum = -1;
for (int i = 0; i < n; i++)
{
if ((r[i] - l[i] + 1)*h[i] > sum)
sum = (r[i] - l[i] + 1)*h[i];
}
cout << sum << endl;
}
return 0;
}
杭电1505
原题连接: http://acm.hdu.edu.cn/showproblem.php?pid=1505
大意就是,有一个大矩形,但是里边有各种填充的小矩形,求空闲区域的最大矩形的面积。
这题和上面写的1506稍有区别,由一维变成了二维,所以,需要将每个位置,都找到“高度”h[i][j]。如果h[i-1][j]是空闲的,那么h[i][j]=h[i-1][j]+1,否则就置为0。然后用L和R两个二维数组分别存储当前位置的左右界。最后循环找出最大值即可。
但是,在其他博客上看到有人说,如果用两个二维数组可能会超时,于是用了两个一维数组,每行都用一遍一维数组,紧接着就判断是否超过当前最大值,然后下一行同样的操作,直到所有行结束。
杭电1087
原题连接: http://acm.hdu.edu.cn/showproblem.php?pid=1087
大意是,给一串数字,从头开始往后走,必须按递增顺序走,求从头走到尾的最大和。
如: start-1 5 7 2 6 9-end 最大和路径为 start-1 5 7 9-end,结果为22
dp[i]表示选择第i个元素后,到目前为止的最大值。
dp[i]=max{ dp[j] }+a[i] 其中,a[i]
杭电1069
原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=1069
题意是:有各种类型的箱子,给定每种箱子的长宽高,而且每种箱子有无数个。现在把箱子往上堆,下面的箱子的长和宽必须全比下面的大,才能把箱子放上去,求最大高度。
思路:虽说每种箱子个数无限多,但其实最多只用三次。首先把箱子按照特定的大小顺序排序,然后从下往上堆。
d[i]表示用到第i个箱子,到目前为止的最大高度。
d[i]=max{ d[j] } + h[i] 其中第j个箱子必须能够放在上面。
下面是代码:
#include <iostream>
#include <algorithm>
using namespace std;
struct xiangzi{
long long x;
long long y;
long long z;
}a[100];
bool cmp(xiangzi a1, xiangzi a2){
if (a1.x > a2.x)
return true;
else if (a1.x == a2.x && a1.y > a2.y)
return true;
else
return false;
}
void swa(int a1){//开始因为这里WA了,不能传进结构体去,要传索引,要不然交换不了
if (a[a1].x>a[a1].y){
long long temp = a[a1].x;
a[a1].x = a[a1].y;
a[a1].y = temp;
}
}
int main()
{
int n;
int kase = 0;
while (true)
{
cin >> n;
if (n == 0) break;
for (int i = 0; i < n; i++){
long long x1, y1, z1;
cin >> x1 >> y1 >> z1;
//scanf("%d%d%d", &x1, &y1, &z1);
a[i * 3].x = a[i * 3 + 1].y = a[i * 3 + 2].z = x1;
a[i * 3].y = a[i * 3 + 1].z = a[i * 3 + 2].x = y1;
a[i * 3].z = a[i * 3 + 1].x = a[i * 3 + 2].y = z1;
swa(i * 3); swa(i * 3 + 1); swa(i * 3 + 2);
}
sort(a, a + n * 3, cmp);
long long d[100] = { 0 };
d[0] = a[0].z;
for (int i = 1; i < 3*n; i++){
long long mymax = 0;
for (int j = 0; j < i; j++){
if (d[j]>mymax && (a[j].x>a[i].x && a[j].y>a[i].y)) mymax = d[j];
}
d[i] = mymax + a[i].z;
}
long long ans = 0;
for (int i = 0; i < 3*n; i++) ans = max(ans, d[i]);
cout << "Case "<< ++kase <<": maximum height = " <<ans << endl;
}
return 0;
}
杭电2571
原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=2571
题目大意是 有n*m的矩阵,每个元素位置都有数字(绝对值不超过100),现在从k[1][1]位置出发,到达k[n][m]位置,途中经过的位置对应数字的和达到最大。其中,从(i,j)点可以直接移动到(i+1,j) (i,j+1) (i, j*p) p>1。
这题其实也是和前边几个思路类似,只是将一维换成了二维。d[i][j]表示到达i,j位置,目前为止的最大值。那么:
其中d[x][y]是上一步能跳到i,j位置的其他所有位置。
下面的代码通过了样例,又是WA:
#include <iostream>
#include <algorithm>
#include "math.h"
using namespace std;
int k[25][1005] = { 0 };
int d[25][1005] = { -105 };
int main()
{
int t;
cin >> t;
while (t--){
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
cin >> k[i][j];
}
}
d[1][1] = k[1][1];
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
int ans = d[i - 1][j];
ans = max(ans, d[i][j - 1]);
for (int p = 2; p <= sqrt(j); p++){
if (j%p == 0)
ans = max(ans, d[i][j / p]);
}
if (i != 1 || j != 1) //填充非d[1][1]的位置的元素
d[i][j] = ans + k[i][j];
}
}
cout << d[n][m] << endl;
}
return 0;
}