首页 > 其他 > 详细

cf235,D Roman and Numbers(状态压缩dp)引发对dp中几种状态类型的思考

时间:2014-03-21 00:33:50      阅读:390      评论:0      收藏:0      [点我收藏+]

由本题思考到dp问题的几种状态类型:

对于数据保存在数组a[n],求解关于这n个数的相关的最优解或计数问题.

(1)线性dp,每个状态表示为一个下标i(或者说是一个固定起点的区间[0, i])(可以说是起点固定的区间dp)

(2)区间dp,每个状态表示为一个区间[i, j];(枚举的过程考虑的整个区间的所有组合情况(区间组合的顺序)。

(3)状态压缩dp(集合上的dp),每个状态表示一个多个元素的集合。(枚举的过程可考虑到集合所有点的全排列情况(点的排列顺序))(与前面不同的是,元素之间没有特定小标的位置要求)

而集合表示的含义,根据具体问题有可有不同的意思。

1)即简单的集合的含义。

2) 最优匹配对的问题。每个集合表示集合中所有点所能构成的最有匹配问题。

3)集合的所有元素的全排列情况

      tsp问题。每个集合表示的是集合中所有点的全排列之后,得到的路径的最优路径值。

      本题。和tsp问题类似。每个集合表示的是集合中所有点的全排列之后,能到的所有数字的取模值。 

各种状态的具体含义,根据具体问题有可有不同的意思。


D Roman and Numbers

cf235 div2, D Roman and Numbers(状态压缩dp)

下面几乎是本场cf第一名的解法


本题题意:给定数字n(10e18以内)和m(100以内),数字的各位重新排列后得到的能被m整除的数的个数.

(1)即18个数(0~9)(包含重复的数子),组成的所有排列数字能被m整数的数的个数

共18!种情况,优化是必须的。最后在用的是集合状态表示,每个集合表示的含义是,所有元素的全排列的模的情况,所以状态压缩。

(2)尤其注意判重的方法:保证对于同一个串数,只在其后面添加不重复的数字。!!!


//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)

typedef long long LL;
const int INF = 1000000007;
const double eps = 1e-10;
const int maxn = 550010;

int n, m;
LL dp[1 << 18][100];
vector<int>a;

int main ()
{
    char s[20];
    cin >> s >> m;
    int n = strlen(s);
    for (int i = 0; i < n; i++) a.push_back(s[i] - ‘0‘);
    sort(a.begin(), a.end());///!!!
    int ALL = (1 << n) - 1;
    dp[0][0] = 1;
    for (int r = 0; r <= ALL; r++)
        for (int i = 0; i < m; i++) if (dp[r][i])
        {
            int x = i * 10;///将下个数插到最后!!!
            int pre = -1;
            for (int j = 0; j < n; j++) if (!(r & (1 << j)))
            {
                if ((r == 0 && a[j] == 0) || (a[j] == pre)) continue;///保证首位不为0且不重复!!!
                int nowx = (x + a[j]) % m;
                pre = a[j];
                dp[r | (1 << j)][nowx] += dp[r][i];
//                cout << nowx << ‘ ‘ << dp[r][i] << ‘ ‘ << dp[r | (1 << j)][nowx] << endl;
            }
        }
    cout << dp[ALL][0] << endl;
    return 0;
}


/**
(1)重复的问题
(2)与背包的结合
(3)0-1和完全的区别
*/


cf235,D Roman and Numbers(状态压缩dp)引发对dp中几种状态类型的思考,布布扣,bubuko.com

cf235,D Roman and Numbers(状态压缩dp)引发对dp中几种状态类型的思考

原文:http://blog.csdn.net/guognib/article/details/21647461

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!