简单递推

来源:互联网 发布:网络凸凸是什么意思 编辑:程序博客网 时间:2024/05/18 10:21

题目链接:[点这儿].

题意:

给你一个1-9的数字集合,要你从中挑选出n的数字,构成n位数,数字可重复挑选,构成的n位数要满足一个条件:

  • 任意相邻的两个数字之差的绝对值要小于等于2.

问你有多少种构造方式.

解析:

很明显的线性动态规划,首先第i位数字的状态可以根据第i-1位数字的状态转移过来;

dp[i][j]表示第前i位且最后一位为j的构造方案数,那么根据条件:任意相邻的两位数字之差的绝对值不超过2,可以得出状态转移方程:

dpi,j=k=22dpi1,j+k(i<n,jS)

代码:

#include <bits/stdc++.h>using namespace std;int main(){    int T, K = 1;    for (cin >> T; T--; K++) {        int m, n;        cin >> m >> n;        vector<int> arr(m);        vector<vector<int> > dp(n + 1, vector<int>(10, 0));        for (int i = 0; i < m; i++)            cin >> arr[i], dp[0][arr[i]] = 1;        for (int i = 1; i < n; i++)            for (size_t j = 0; j < arr.size(); j++)                for (int k = -2; k <= 2; k++)                    if (arr[j] + k < 10 && arr[j] + k > 0)                        dp[i][arr[j]] += dp[i - 1][arr[j] + k];        int ans = 0;        for (size_t i = 0; i < arr.size(); i++)            ans += dp[n - 1][arr[i]];        cout << "Case " << K << ": " << ans << endl;    }    return 0;}

可以用一个map来代替数组,这样程序的写法会简单,且空间会减少,是一种好的写法.

#include <bits/stdc++.h>using namespace std;int main(){    int T, K = 1;    for (cin >> T; T--; K++) {        int m, n, x;        cin >> m >> n;        map<int, int> dp, tmp;        for (int i = 0; i < m; i++)            dp[cin >> x, x] = 1;        for (int i = 1; i < n; i++) {            for (map<int, int>::iterator it = dp.begin(); it != dp.end(); ++it)                for (int k = -2; k <= 2; k++)                    tmp[it->first] += dp.find(it->first + k) == dp.end() ? 0 : dp[it->first + k];            dp.swap(tmp);            tmp.clear();        }        int ans = 0;        for (map<int, int>::iterator it = dp.begin(); it != dp.end(); ++it)            ans += it->second;        cout << "Case " << K << ": " << ans << endl;    }    return 0;}