整理考研书——最长上升(不降)子序列问题(LIS)

小明非常喜欢计算机,他想在本科毕业后继续读计算机研究生,于是他决定报考明年的研究生考试。最近一段时间小明一直在忙着考研复习,他买了非常多的考研复习书(虽然有很多不一定会看-_-!),其中最喜欢的就是天勤出品的《高分笔记》系列辅导书了,而这些书都无规则的排列在他的书架上。
他的书架有N层,每层放着M本书。现在他决定整理一下杂乱的考研书,每层按照书名的字典序排序。书名可以相同,且书名中只包含大小写字母和空格。比较时,忽略书名中的空格,并且不区分字母大小写。例如,要将“Computer Science”转换成“ComputerScience”,再进行比较,并且“A”与“a”的字典序相同。
由于考研复习时间宝贵,小明想用最短的时间整理好这些顺序杂乱的考研书。小明需要做的操作是每次从某一层书架里挑选出一本书,然后将其插入同一层的任意位置,这一操作会消耗小明一个单位的时间。现在小明想知道最短需要多长时间可以整理好整个书架上的书。

输入

输入包含多组测试数据。
每组第一行输入两个整数N和M(1<=N,M<=100),N表示书架共有N层,M表示每层有M本书。
接下来输入N*M行,每行输入一个书名,书名(包含空格)长度不超过50,第1行~第M行表示第一层书架上的图书序列,第M+1行~第2M行表示第二层书架上的图书序列,以此类推。

输出

对于每组输入,输出整理好所有考研书所需要的最短时间,每组输出占一行。

样例输入 

2 3
Data Structures
Operating System
Computer Networks
Gao Fen Bi Ji
Zhen Ti Jie Xi
Xi Ti Jing Xi Kuo Zhan

样例输出

2

这题就是最长上升子序列的变形,因为要用最少的移动次数把考研书放成升序的,只需要求出最长不降子序列的个数,那剩下的书就是最少需要移动的。只要能看出问题背后的逻辑,这题就很简单了。对书名字符串的处理方式看自己习惯就好,我习惯用string处理,用char字符数组也行,不过用char数组的话速度快些。关键是要能看出核心是最长上升子序列。

#include <iostream>
#include <cstring>
using namespace std;
int n, m, res, dp[105];
string s[105];
int LIS()   //Longest Increasing Subsequence 最长上升子序列
{
    memset(dp, 0, sizeof(dp));
    dp[1] = 1;
    int ans = 1;
    for (int i = 2; i <= m; i++)
    {
        dp[i] = 1;
        for (int j = 1; j < i; j++)
        {
            if (s[j] <= s[i])
            {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        ans = max(ans, dp[i]);
    }
    return ans;
}
int main()
{
    while (scanf("%d %d", &n, &m) != EOF)
    {
        res = 0;
        getchar();
        for (int i = 0; i < n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                getline(cin, s[j]);
                for (int k = 0; k < s[j].size(); k++)
                {
                    if (s[j][k] <= 'Z' && s[j][k] >= 'A')
                        s[j][k] += 32;
                }
                for (int j = 1; j <= m; j++)
                {
                    int tmp = -1;
                    while ((tmp = s[j].find(' ')) != -1)
                        s[j] = s[j].substr(0, tmp) + s[j].substr(tmp + 1);
                }
            }
            res += (m - LIS());  //减去LIS长度即为答案
        }
        cout << res << endl;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值