PAT甲级1045+1048、迭代子模式

1045

题意:给定两个序列a和b,要求从b中找出一个最长的子序列符合各个元素的顺序是a序列的子序列。
题解:容易想到这是一个动态规划,维护一个数组dp[i][j],代表对于a序列的前i个元素组成的子串,可以从b序列的前j个子串中找到的最长子序列。转移方程的一部分和公共最长子序列相同,如下:

            dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            if (a[i] == b[j])
            {
                dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
            }

另外,由于b序列的子序列中,多个相同的连续元素可以对应a序列中的单个元素,所以,还需要维护一个p[i][j]数组,其意思为a序列的前i个元素组成的子串,和b序列中,颜色为j的最长匹配。其转移方式如下:

            dp[i][j] = max(dp[i][j], p[i][b[j]] + 1);
            if (a[i] == b[j])
                p[i][b[j]] = max(p[i][b[j]], dp[i][j]);

代码:

#include <bits/stdc++.h>

using namespace std;

const int Maxn = 205;

const int MaxL = 10004;

int dp[Maxn][MaxL];
int p[Maxn][Maxn];

int N, M, L;
int a[Maxn];
int b[MaxL];

int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    cin >> N;

    cin >> M;
    for (int i = 1; i <= M; i++)
    {
        cin >> a[i];
    }
    cin >> L;
    for (int i = 1; i <= L; i++)
    {
        cin >> b[i];
    }

    for (int i = 1; i <= M; i++)
    {
        for (int j = 1; j <= L; j++)
        {

            dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            if (a[i] == b[j])
            {
                dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
            }
            
            dp[i][j] = max(dp[i][j], p[i][b[j]] + 1);
            if (a[i] == b[j])
                p[i][b[j]] = max(p[i][b[j]], dp[i][j]);
        }
    }

    cout << dp[M][L];
    // cin >> M;
}

1048

题意:给定一个数字和一个序列,从序列中找出两个元素,使得他们的和为这个给定的数字。
题解:容易想到用数组维护序列中每个元素的数量,从1到给定的数字进行遍历,找到即退出循环。
代码:

#include <bits/stdc++.h>

using namespace std;
const int Maxn = 1e5 + 10;
int cnt[Maxn];
int main()
{
    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        cnt[x]++;
    }
    int p1 = -1, p2 = -1;

    for (int i = 0; i <= m && m - i >= i; i++)
    {
        if (cnt[i] && cnt[m - i] && m - i != i)
        {
            p1 = i, p2 = m - i;
            break;
        }
        if (m - i == i && cnt[i] >= 2 && p1 == -1)
        {
            p1 = p2 = i;
        }
    }
    if (p1 == -1)
    {
        cout << "No Solution";
    }
    else
    {
        cout << p1 << " " << p2 << "\n";
    }
    // cin >> n;
}

迭代子模式

迭代子模式的结构
  迭代子模式有两种实现方式,分别是白箱聚集与外禀迭代子和黑箱聚集于内禀迭代子。

白箱聚集与外禀迭代子
  如果一个聚集的接口提供了可以用来修改聚集元素的方法,这个接口就是所谓的宽接口。

如果聚集对象为所有对象提供同一个接口,也就是宽接口的话,当然会满足迭代子模式对迭代子对象的要求。但是,这样会破坏对聚集对象的封装。这种提供宽接口的聚集叫做白箱聚集。聚集对象向外界提供同样的宽接口
  
由于聚集自己实现迭代逻辑,并向外部提供适当的接口,使得迭代子可以从外部控制聚集元素的迭代过程。这样一来迭代子所控制的仅仅是一个游标而已,这种迭代子叫做游标迭代子(Cursor Iterator)。由于迭代子是在聚集结构之外的,因此这样的迭代子又叫做外禀迭代子(Extrinsic Iterator)。

现在看一看白箱聚集与外禀迭代子的实现。一个白箱聚集向外界提供访问自己内部元素的接口(称作遍历方法或者Traversing Method),从而使外禀迭代子可以通过聚集的遍历方法实现迭代功能。

因为迭代的逻辑是由聚集对象本身提供的,所以这样的外禀迭代子角色往往仅仅保持迭代的游标位置。

一个典型的由白箱聚集与外禀迭代子组成的系统如下图所示,在这个实现中具体迭代子角色是一个外部类,而具体聚集角色向外界提供遍历聚集元素的接口。
  迭代子模式涉及到以下几个角色:

●  抽象迭代子(Iterator)角色:此抽象角色定义出遍历元素所需的接口。

●  具体迭代子(ConcreteIterator)角色:此角色实现了Iterator接口,并保持迭代过程中的游标位置。

●  聚集(Aggregate)角色:此抽象角色给出创建迭代子(Iterator)对象的接口。

●  具体聚集(ConcreteAggregate)角色:实现了创建迭代子(Iterator)对象的接口,返回一个合适的具体迭代子实例。

●  客户端(Client)角色:持有对聚集及其迭代子对象的引用,调用迭代子对象的迭代接口,也有可能通过迭代子操作聚集元素的增加和删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值