最长单调子序列

最长单调子序列

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;
}


 

你可能感兴趣的:(算法,DP)