hdu 1160 最长上升子序列 + 记录路径

来源:互联网 发布:上古卷轴rm捏脸数据 编辑:程序博客网 时间:2024/06/10 08:01

FatMouse's Speed

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 17321    Accepted Submission(s): 7668
Special Judge


Problem Description
FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the speeds are decreasing.
 

Input
Input contains data for a bunch of mice, one mouse per line, terminated by end of file.

The data for a particular mouse will consist of a pair of integers: the first representing its size in grams and the second representing its speed in centimeters per second. Both integers are between 1 and 10000. The data in each test case will contain information for at most 1000 mice.

Two mice may have the same weight, the same speed, or even the same weight and speed. 
 

Output
Your program should output a sequence of lines of data; the first line should contain a number n; the remaining n lines should each contain a single positive integer (each one representing a mouse). If these n integers are m[1], m[2],..., m[n] then it must be the case that 

W[m[1]] < W[m[2]] < ... < W[m[n]]

and 

S[m[1]] > S[m[2]] > ... > S[m[n]]

In order for the answer to be correct, n should be as large as possible.
All inequalities are strict: weights must be strictly increasing, and speeds must be strictly decreasing. There may be many correct outputs for a given input, your program only needs to find one. 
 

Sample Input
6008 13006000 2100500 20001000 40001100 30006000 20008000 14006000 12002000 1900
 

Sample Output
44597
 

Source
Zhejiang University Training Contest 2001

这题我不看题解做了三天,首先感觉自己还是比较菜,然后也比较高兴,毕竟终于做出来了。
说一下题意:就是给你不大于以前只老鼠的体重和速度,然后要你把其中任意的老鼠按体重越来越大,速度越来越小的规律排列,得出最大排列的老鼠数目,然后把该排列老鼠从头到尾输出在原来序列的序号。

注意:输入结束为:ctrl + z  不理解的话,自己输入时按一下 ctrl + z 就知道了。

接下来说说题解:
简单来说就是先sort 一遍,然后求最大上升子序列并在期间记录序号,最后逆序输出。
然后是详解:
输入时记录老鼠在原来的序号只要用个数组记录,例如:
    maps[mice[cnt].wei][mice[cnt].spd] = cnt + 1; 
    其中,mice  是记录老鼠体重和速度的结构体,cnt 是 老鼠的序号(cnt + 1是因为一开始时 cnt = 0),wei      是老      鼠的体重,spd 是老鼠的速度, maps 就是记录序号的数组。

输入完成后先用 sort 按老鼠体重越来越大,速度越来越小的条件排一下序,排序的条件设置可以直接在结构体里设置,像这样:
struct node
{
    int wei, spd;
    int num;
    bool operator < (node bb)
    {
        if(this -> wei == bb.wei) return this -> spd < bb.spd;
        return this -> wei < bb.wei;
    }
}mice[maxn];
其中,bool 是返回值类型,operator 是运算符重载的意思,重载的意思举个例子,比如 < 号在c++里不重载时只能比较整型和浮点型数字变量的大小,而不能比较结构体变量里元素的大小,现在把它重载就可以了, “ < ”就是要重载的运算符,node bb 表示 a < b 里的 b,this -> wei  和 this -> spd  表示  a < b 里的 a 的元素wei 和 spd,大概就是这么个意思,具体的解释看c++书里讲重载那章吧。
    然后,很明显这样就变成最大上升子序列 + 记录路径求法了,由于老鼠最多有1e3 只,那么就只需要用时间复杂度为n ^ 2 的求最大上升子序列的方法就行了,如果用时间复杂度为 nlog(n)的那种方法是很麻烦的。(如果不太明白我这句话的童鞋可以上网搜搜“最大上升子序列 nlog(n)”)
然后在求时就要用一个index数组构造最优解:记录每一项接在哪一项后面
最后用counter找出最大的dp[0…n], pp记录下标,回溯输出即可。





附上代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;
///o(っ。Д。)っ AC万岁!!!!!!!!!!!!!!
const int maxn = 10090;
struct node
{
    int wei, spd;
    int num;
    bool operator < (node bb)
    {
        if(this -> wei == bb.wei) return this -> spd < bb.spd;
        return this -> wei < bb.wei;
    }
}mice[maxn];
int maps[maxn][maxn];
int dp[maxn] = {}, index[maxn] ={};
void dfs(int counter)
{
    if(index[counter] != -1) dfs(index[counter]);
    printf("%d\n", maps[mice[counter].wei][mice[counter].spd]);
}
int main()
{
    int cnt = 0;
    while(~scanf("%d %d", &mice[cnt].wei, &mice[cnt].spd))
    {
        mice[mice[cnt].wei].num = cnt + 1;
        maps[mice[cnt].wei][mice[cnt].spd] = cnt + 1;
        cnt++;
    }
    sort(mice, mice + cnt);
    memset(index, -1, sizeof(index));
    int counter = 0;
    for(int i = 1; i < cnt; i++)
    {
        if(mice[i].wei == mice[i - 1].wei && mice[i].spd == mice[i - 1].spd) continue;
        for(int j = 0; j < i; j++)
        {
            if(mice[i].wei > mice[j].wei && mice[i].spd < mice[j].spd && dp[i] <= dp[j])
            {
                index[i] = j;
                dp[i] = dp[j] + 1;
            }
        }
    }
    int pp;
    for(int i = 1; i <= cnt; i++)
    {
        if(counter <= dp[i])
        {
            counter = dp[i];
            pp = i;
        }
    }
    printf("%d\n", counter + 1);
    dfs(pp);
    return 0;
}
/*
100 500
2000 4000
3000 1900
500 2000
4000 300
600 1100


1000 2000
500 400
1001 2100
2000 200
300 4000
1100 1100
300 4000
*/






阅读全文
0 0