一道一开始不知道是用DP的题目 也许是对DP的理解不深 看了题解之后发现很容易...
思路
两个变量, 输入的左边是W 右边是 S 要找一条最长的序列使得W是递增而S是递减的
明白题意后第一个肯定是做一个排序啦, 一开始是按题意W按小到大 W相等就S大到小
结果看了题解之后发现W从大到小 W相等S从小到大利于优化
题目的输出有两个元素 第一个是这个序列的长度
之后输出这个序列的输入顺序 这里可能有点绕口 就是说输出的数字代表的是第几个输入的数
因为排序会破坏原来输入的顺序, 所以要有一个东西来保留这个数的输入顺序
这里用的是结构体 :
n代表这个数的输入顺序 , w s 表示输入的W 和S ,last就是用来记录这个num 的上一个num是哪一个num
排序之后呢DP就开始了!!!!
因为这里是W按大到小排序的 所以需要两个循环用来比较i和i之前的W 这里比较重要的是比较S
案例里面有一个例子是有三个6000的 比较W就是用在这个地方 因为W相等的话S是从小到大 而在这种情况中 根据这种排序方法能快速找到最后可能的 S与前面的num匹配为符合题目条件的序列
符合条件后就开始寻找最大长度 dp[i] 的意思是第 i 个元素时的序列长度为dp[i] 之后就是不断找出直到循环结束
输出一个序列的长度
后从最后一个开始 如果最后一个的上一个num不为0(从一条串的低端往上数,直到这条串的第一个节点时 num.last为0 用last就是这么个意思)
倒序输出顺序,因为一开始排序的按题目相反的顺序排的 所以此时倒序输出恰为正确的顺序!!!
上代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1005;
const int INF = 0x3f3f3f3f;
struct node
{
int n, l, w, s;
} num[N];
int cmp(node a, node b)
{
if(a.w == b.w) return a.s < b.s;
return a.w > b.w;
}
int dp[N];
int main()
{
int c = 1;
while(~scanf("%d %d",&num[c].w, &num[c].s))
{
num[c].n = c;
num[c].l = 0;
c++;
}
sort(num + 1, num + c + 1, cmp);
num[0].w = INF;
num[0].l = 0;
num[0].s = 0;
num[0].n = 0;
int ans = 0;
for (int i = 1; i <= c; i++)
{
dp[i] = 1;
for (int j = 0; j < i; j++)
{
if (num[j].w > num[i].w && num[j].s < num[i].s)
{
if (dp[j] + 1 >= dp[i])
{
dp[i] = dp[j] + 1;
num[i].l = j;
if (dp[i] > dp[ans])
{
ans = i;
}
}
}
}
}
printf("%d\n", dp[ans]);
while (num[ans].l)
{
printf("%d\n", num[ans].n);
ans = num[ans].l;
}
printf("%d\n", num[ans].n);
return 0;
}