ZOJ 1100 Mondriaan's Dream

一道一开始不知道是用DP的题目  也许是对DP的理解不深 看了题解之后发现很容易...

思路

     两个变量, 输入的左边是W 右边是 S 要找一条最长的序列使得W是递增而S是递减的

明白题意后第一个肯定是做一个排序啦, 一开始是按题意W按小到大 W相等就S大到小

结果看了题解之后发现W从大到小 W相等S从小到大利于优化

题目的输出有两个元素 第一个是这个序列的长度  

之后输出这个序列的输入顺序  这里可能有点绕口  就是说输出的数字代表的是第几个输入的数

因为排序会破坏原来输入的顺序, 所以要有一个东西来保留这个数的输入顺序

这里用的是结构体 :

   n代表这个数的输入顺序 , w s 表示输入的W 和S ,last就是用来记录这个num 的上一个num是哪一个num

排序之后呢DP就开始了!!!!

扫描二维码关注公众号,回复: 1460994 查看本文章

因为这里是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;
}

猜你喜欢

转载自blog.csdn.net/dioml/article/details/50916236