一道一开始不知道是用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; }