最长单调子序列
1. 问题描述(HDU 1160)
给出一些老鼠的质量和速度, 求一串数据证明老鼠的质量和速度成反比例关系?
2. 算法介绍
首先排序(由小到大), 第一关键字“质量”, 第二关键字“速度“
最长单调子序列方法:
Len(i)表示使证明成立的某串数据最后一只老鼠是第 i 只老鼠的该串长度。
对于第i + 1 只老鼠, Len(i + 1)= max (Len (j) + 1, Len(i + 1)) 且 满足速度和质量成反比例关系。
对于 HDU 1160 , 还需求出具体是哪些老鼠, 用一个数组记录上一个老鼠, 递归输出即可。
3. 简单应用
HDU 1421 搬寝室
按重量排序,相邻的两个物品所产生的疲劳度最小。 dp[i][j] 表示i个物品中取j对物品的最低疲劳度 如果j对物品中包含i物品,dp[i][j] = dp[i - 2][j - 1] + i物品 与 i - 1 物品的差的平方; 如果不包含, dp[i][j] = dp[i - 1][j];
HDU 1069 monkey and banana
本题与普通的字符串的最大区别在于字符串中的字符位置是不变的,而方块是可以任意选取的,
因此我们只需要确定每一个方块的位置(方块即字符串中的一个字符)就行了。
本题有多重确定方块位置的方法,可以按面积排序,或者按边长排序都行,其本质都是确保
前面的方块都能放在其后的某个方块的下面,然后按照求最长单调子序列的方法求解即可。
本题的另一个注意点就是,x, y的选取, 一个立方体有三个面可以作为底面,而一个面的长或宽有两种选择
所以本题的底面有6种情况。
HDU 2059 龟兔赛跑
记录从起点开始到其他各点的最短时间。
最短时间是从点i开始,从起点到i的最短时间 + 开车时间 + 加油时间 + 脚踩到点j所花去的时间(如果需要)总和
即为起点到J的最短时间。 (好好理解这个方程, 想想最长单调子序列的方法, 两个循环)
为什么这个方程是对的?
因为,最短时间的来就是选取在哪个站加油,每个站都有可能。而上面的DP,则在每个站点都加一次油,然后一直开,就考虑了
所有的可能加油的站点。
4. 源代码
HDU 1160
#include
#include
struct Mouse
{
int weight;
int speed;
int index;
int pre;
}M[1000];
int num[1000];
int cmp (const void *a, const void *b);
void print (int max);
int main()
{
int i, j;
int n, max;
i = 0;
while (scanf ("%d%d", &M[i].weight, &M[i].speed) == 2)
{
M[i].index = i + 1;
i ++;
}
n = i;
qsort (M, n, sizeof (struct Mouse), cmp);
for (i = 0; i < n; i ++)
{
num[i] = 1;
M[i].pre = i;
}
for (i = 0; i < n; i ++)
{
for (j = 0; j < i; j ++)
{
if (M[i].weight > M[j].weight && M[i].speed < M[j].speed && num[i] < num[j] + 1)
{
num[i] = num[j] + 1;
M[i].pre = j;
}
}
}
max = 0;
for (i = 0; i < n; i ++)
{
if (num[i] > num[max])
{
max = i;
}
}
printf ("%d\n", num[max]);
print (max);
return 0;
}
int cmp (const void *a, const void *b)
{
struct Mouse *v1 = (struct Mouse *)a;
struct Mouse *v2 = (struct Mouse *)b;
if (v1->weight != v2->weight)
{
return v1->weight - v2->weight;
}
else
{
return v2->speed -v1->speed;
}
}
void print (int max)
{
int i = max;
if (M[i].pre != i)
{
print (M[i].pre);
printf ("%d\n", M[i].index);
}
else
{
printf ("%d\n", M[i].index);
}
}
HDU 1421
#include
#include
#include
#define MAX 100000000
int weight[2001];
int dp[2001][1001];
int cmp (const void *a, const void *b);
int main()
{
int i, j;
int n, k;
while (scanf ("%d%d",&n, &k) == 2)
{
for (i = 1; i <= n; i ++)
{
scanf ("%d", &weight[i]);
}
qsort (weight + 1, n, sizeof (int), cmp); // 从weight[1]开始排序
for (i = 0; i <= n; i ++)
{
for (j = 1; j <= k; j ++)
{
dp[i][j] = MAX;
}
}
for (i = 2; i <= n; i ++)
{
for (j = 1; j <= k && 2 * j <= i; j ++)
{
dp[i][j] = dp[i - 2][j - 1] + (weight[i] - weight[i - 1]) * (weight[i] - weight[i - 1]);
if (dp[i - 1][j] < dp[i][j])
{
dp[i][j] = dp[i - 1][j];
}
}
}
printf ("%d\n", dp[n][k]);
}
return 0;
}
int cmp (const void *a, const void *b)
{
return *((int *)a) - *((int *)b);
}
HDU 1069
#include
#include
#include
struct Shape
{
int x;
int y;
int z;
}s[541];
int cmp (const void *a, const void *b);
int height[540];
int main()
{
int n;
int i, j;
int x, y, z;
int count, max;
count = 1;
while (scanf ("%d", &n) == 1 && n)
{
j = 0;
for (i = 0; i < n; i ++)
{
scanf ("%d%d%d", &x, &y, &z);
s[j].x = x;
s[j].y = y;
s[j ++].z = z;
s[j].x = y;
s[j].y = z;
s[j ++].z = x;
s[j].x = x;
s[j].y = z;
s[j ++].z = y;
s[j].x = y;
s[j].y = x;
s[j ++].z = z;
s[j].x = z;
s[j].y = y;
s[j ++].z = x;
s[j].x = z;
s[j].y = x;
s[j ++].z = y;
}
qsort (s, 6 * n, sizeof (struct Shape), cmp);
memset (height, 0, sizeof (height));
max = 0;
for (i = 0; i < 6 * n; i ++)
{
for (j = 0; j < i; j ++)
{
if (s[j].x > s[i].x && s[j].y > s[i].y)
{
if (height[i] < height[j])
{
height[i] = height[j];
}
}
}
height[i] += s[i].z;
if (max < height[i])
{
max = height[i];
}
}
printf ("Case %d:", count ++);
printf (" maximum height = %d\n", max);
}
return 0;
}
int cmp (const void *a, const void *b) // 边长排序
{
struct Shape *v1 = (struct Shape *)a;
struct Shape *v2 = (struct Shape *)b;
if (v1->x != v2->x)
{
return v2->x - v1->x;
}
else if(v1->y != v2->y)
{
return v2->y - v1->y;
}
else
{
return v2->z - v1->z;
}
}
/*int cmp (const void *a, const void *b) // 面积排序
{
struct Shape *v1 = (struct Shape *)a;
struct Shape *v2 = (struct Shape *)b;
int area1, area2;
area1 = v1->x * v1->y;
area2 = v2->x * v2->y;
if (area1 != area2)
{
return area2 - area1;
}
else
{
return v2->z - v1->z;
}
}*/
HDU 2059
#include
int main()
{
int len;
int i, j;
int N, D, T;
double t1, t2;
int vr, vt1, vt2;
int station[102];
double dp[102];
while (scanf ("%d", &len) == 1)
{
scanf ("%d%d%d", &N, &D, &T);
scanf ("%d%d%d", &vr, &vt1, &vt2);
for (i = 1; i <= N; i ++)
{
scanf ("%d", &station[i]);
}
t1 = (double)len / vr;
for (i = 1; i < N + 2; i ++)
{
dp[i] = 1000000;
}
dp[0] = 0;
station[0] = 0;
station[N + 1] = len; // 加入起点和终点
for (i = 1; i < N + 2; i ++)
{
for (j = 0; j < i; j ++)
{
if (station[i] - station[j] <= D)
{
t2 = (station[i] - station[j]) / (double)vt1;
}
else
{
t2 = D / (double)vt1 + (station[i] - station[j] - D) / (double)vt2;
}
if (j != 0)
{
t2 += T; // 起点油已经加满,其他各点均需要加油,花费时间T
}
if (dp[i] > t2 + dp[j])
{
dp[i] = t2 + dp[j];
}
}
}
if (t1 < dp[N + 1])
{
printf ("Good job,rabbit!\n");
}
else
{
printf ("What a pity rabbit!\n");
}
}
return 0;
}