一道求最长上升子序列的变形题,较简单的动态规划。题意:普遍认为老鼠体重越重的话,行动的速度就越慢,现在在文件中输入每一个老鼠的体重和速度信息,老鼠编号从1开始,要求选出最多的老鼠排成序列,使得老鼠的体重严格递增,速度严格递减,请输出这个序列的老鼠个数以及按顺序输出这个序列的老鼠编号。
我的解题思路:首先输入中并没有给出老鼠的总数,所以我们要一边输入一边计算老鼠的个数,顺便给每一个老鼠编号。不使用下标来编号的原因是因为接下来要排序。因为有体重和速度两种权,我们先将其中一种权排序,之后就可以直接在另一个权上使用求最长上升子序列的解法了。比如:当我们已经按体重从小到大的顺序给老鼠排好序了,那么我们假设dp[i]表示当编号为i的老鼠为这个序列中最后一个老鼠时,这个序列的最大长度,那么dp[i] = max(dp[j]) + 1,其中(1<=j<i && speed[j] > speed[i])。然后最长的序列长度就是最大的dp,至于按顺序输出老鼠编号序列,还是老方法,在记录dp时顺便存下前一个老鼠的编号,最后从终点往起点记录路径再输出就行了。当然,或者你也可以存下一个老鼠的编号,这样你可以直接从起点输出路径直到终点就ok了(貌似这样更加简单些)。
我的解题代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
#define N 1003
struct mouse
{
int weight; //体重
int speed; //速度
int id; //编号
};
struct DP
{
int pi; //当构成序列的前一个下标
int len; //长度
};
mouse m[N];
DP dp[N];
int n; //老鼠数量
stack <int> s; //用于存储编号的栈
void Init(); //初始化
void Read(); //输入
int Mycmp(const void *a, const void *b); //排序比较函数
void DataProcess(); //数据处理
int main()
{
Init();
Read();
qsort(&m[1], n, sizeof(mouse), Mycmp);
DataProcess();
return 0;
}
void Init()
{
for (int i=0; i<N; ++i)
{
dp[i].pi = 0;
}
n = 1;
return;
}
void Read()
{
while (~scanf("%d %d", &m[n].weight, &m[n].speed))
{
m[n].id = n;
++n;
}
return;
}
int Mycmp(const void *a, const void *b)
{
if ((*(mouse *)a).weight != (*(mouse *)b).weight) //优先按照体重排序
{
return (*(mouse *)a).weight - (*(mouse *)b).weight;
}
return (*(mouse *)b).speed - (*(mouse *)a).speed;
}
void DataProcess()
{
dp[1].len = 1;
int anslen = 1; //构成序列的老鼠个数
int ansi = 1; //构成序列的最后一个老鼠的下标
for (int i=2; i<n; ++i)
{
int maxlen = 1;
int maxi = 0;
for (int j=i-1; j>0; --j)
{
if (dp[j].len >= maxlen && m[j].speed > m[i].speed && m[j].weight < m[i].weight)
{
maxlen = dp[j].len + 1;
maxi = j;
}
}
dp[i].len = maxlen;
dp[i].pi = maxi;
if (dp[i].len > anslen)
{
anslen = dp[i].len;
ansi = i;
}
}
printf("%d\n", anslen);
while (ansi != 0) //路径存栈
{
s.push(m[ansi].id);
ansi = dp[ansi].pi;
}
while (!s.empty()) //输出路径
{
printf("%d\n", s.top());
s.pop();
}
return;
}