• vijos P1426兴奋剂检查 多维费用背包问题的hash


    https://vijos.org/p/1426

    这是个好题,容易想到用dp[i][v1][v2][v3][v4][v5]表示在前i个物品中,各种东西的容量是那个的时候,能产生的最大价值。

    时间不会TLE,但是会MLE.所以就需要把那5维状态进行hash

    其实就是对这个排列进行一个hash。

    newState: v1, v2, v3, v4, v5这个排列。

    oldState: v1 - w[1], v2 - w[2], v3 - w[3], v4 - w[4], v5 - w[5]

    这个排列。

    然后要进行hash。我写了一个hash。TLE 两组数据。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 200 + 20;
    int dp[5000000 + 20];
    int limit[maxn];
    int w[maxn][10];
    int val[maxn];
    int togive;
    const int seed = 131;
    typedef unsigned long long int ULL;
    ULL powseed[10];
    int first[100003 + 2];
    ULL Edge[5000000 + 20];
    int tonext[5000000 + 20];
    int id[5000000 + 20];
    int num;
    int toadd(ULL val) {
        int u = val % 100003;
        for (int i = first[u]; i; i = tonext[i]) {
            if (val == Edge[i]) return id[i];
        }
        ++num;
        tonext[num] = first[u];
        first[u] = num;
        Edge[num] = val;
        id[num] = ++togive;
        return togive;
    }
    int tohash(int a, int b, int c, int d, int e) {
        ULL val = a * powseed[1] + b * powseed[2] +
                  c * powseed[3] + d * powseed[4] + e * powseed[5];
        return toadd(val);
    }
    //适用于正负整数
    template <class T>
    inline bool fast_in(T &ret) {
        char c;
        int sgn;
        if(c = getchar(), c == EOF) return 0; //EOF
        while(c != '-' && (c < '0' || c > '9')) c = getchar();
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
        ret *= sgn;
        return 1;
    }
    void work() {
        int n, m;
    //    cin >> n >> m;
    //    scanf("%d%d", &n, &m);
        fast_in(n);
        fast_in(m);
        for (int i = 1; i <= m; ++i) {
    //        cin >> limit[i];
    //        scanf("%d", &limit[i]);
            fast_in(limit[i]);
        }
        for (int i = 1; i <= n; ++i) {
    //        cin >> val[i];
    //        scanf("%d", &val[i]);
            fast_in(val[i]);
            for (int j = 1; j <= m; ++j) {
    //            cin >> w[i][j];
    //            scanf("%d", &w[i][j]);
                fast_in(w[i][j]);
            }
        }
    //    cout << tohash(1, 2, 3, 4, 5) << endl;
    //    cout << tohash(1, 2, 4, 3, 5) << endl;
    //    cout << tohash(1, 2, 3, 4, 5) << endl;
        int ans = 0;
        for (int i = 1; i <= n; ++i) {
            for (int a1 = limit[1]; a1 >= w[i][1]; --a1) {
                for (int a2 = limit[2]; a2 >= w[i][2]; --a2) {
                    for (int a3 = limit[3]; a3 >= w[i][3]; --a3) {
                        for (int a4 = limit[4]; a4 >= w[i][4]; --a4) {
                            for (int a5 = limit[5]; a5 >= w[i][5]; --a5) {
                                int now = tohash(a1, a2, a3, a4, a5);
                                int pre = tohash(a1 - w[i][1], a2 - w[i][2], a3 - w[i][3], a4 - w[i][4], a5 - w[i][5]);
                                dp[now] = max(dp[now], dp[pre] + val[i]);
                                ans = max(ans, dp[now]);
                            }
                        }
                    }
                }
            }
        }
        printf("%d
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        powseed[0] = 1;
        for (int i = 1; i <= 5; ++i) {
            powseed[i] = powseed[i - 1] * seed;
        }
        work();
        return 0;
    }
    View Code

    题解的那个hash我真看不懂。不是看不懂,是不理解。

    其实他的意思类似于a * 1000000 + b * 100000 + c * 1000 + e * 100 * d * 10

    这样类似的。但是明显这个值太大了。他就乘上了limit[i],这个我不能证明了,

    好像又不会重复,数字又小。ORZ

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 200 + 20;
    int dp[5000000 + 20];
    int limit[maxn];
    int w[maxn][10];
    int val[maxn];
    
    int tohash(int a, int b, int c, int d, int e) {
        return (a * (limit[2] + 1) * (limit[3] + 1) * (limit[4] + 1) * (limit[5] + 1)
                + b * (limit[3] + 1) * (limit[4] + 1) * (limit[5] + 1)
                + c * (limit[4] + 1) * (limit[5] + 1) + d * (limit[5] + 1) + e);
    }
    //适用于正负整数
    template <class T>
    inline bool fast_in(T &ret) {
        char c;
        int sgn;
        if(c = getchar(), c == EOF) return 0; //EOF
        while(c != '-' && (c < '0' || c > '9')) c = getchar();
        sgn = (c == '-') ? -1 : 1;
        ret = (c == '-') ? 0 : (c - '0');
        while(c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
        ret *= sgn;
        return 1;
    }
    void work() {
        int n, m;
    //    cin >> n >> m;
    //    scanf("%d%d", &n, &m);
        fast_in(n);
        fast_in(m);
        for (int i = 1; i <= m; ++i) {
    //        cin >> limit[i];
    //        scanf("%d", &limit[i]);
            fast_in(limit[i]);
        }
        for (int i = 1; i <= n; ++i) {
    //        cin >> val[i];
    //        scanf("%d", &val[i]);
            fast_in(val[i]);
            for (int j = 1; j <= m; ++j) {
    //            cin >> w[i][j];
    //            scanf("%d", &w[i][j]);
                fast_in(w[i][j]);
            }
        }
    //    cout << tohash(1, 2, 3, 4, 5) << endl;
    //    cout << tohash(1, 2, 4, 3, 5) << endl;
    //    cout << tohash(1, 2, 3, 4, 5) << endl;
        int ans = 0;
        for (int i = 1; i <= n; ++i) {
            for (int a1 = limit[1]; a1 >= w[i][1]; --a1) {
                for (int a2 = limit[2]; a2 >= w[i][2]; --a2) {
                    for (int a3 = limit[3]; a3 >= w[i][3]; --a3) {
                        for (int a4 = limit[4]; a4 >= w[i][4]; --a4) {
                            for (int a5 = limit[5]; a5 >= w[i][5]; --a5) {
                                int now = tohash(a1, a2, a3, a4, a5);
                                int pre = tohash(a1 - w[i][1], a2 - w[i][2], a3 - w[i][3], a4 - w[i][4], a5 - w[i][5]);
                                dp[now] = max(dp[now], dp[pre] + val[i]);
                                ans = max(ans, dp[now]);
                            }
                        }
                    }
                }
            }
        }
        printf("%d
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
        work();
        return 0;
    }
    View Code

    感觉我的hash才是正确的打开方式

  • 相关阅读:
    IOS 改变UISearchBar的背景色
    电话正则表达式
    理解Callable 和 Spring DeferredResult(翻译)
    Java设计模式——观察者模式(事件监听)
    SpringMVC注解@initbinder解决类型转换问题
    内部系统间调用client包的封装方法
    Java中Comparable和Comparator实现对象比较
    linux上FTP服务器搭建
    百度地图——判断用户是否在配送范围内解决方案
    nodejs之express的使用
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6404008.html
Copyright © 2020-2023  润新知