zoukankan      html  css  js  c++  java
  • Gym

    G. Training Camp
    [ Color: Yellow ]
    Montaser is planning to train very hard for ACM JCPC 2015; he has prepared a list with n topics
    to study in the next n days, one topic every day.
    Montaser knows that some topics depend on other topics, so he asked coach Fegla and got a list
    of m constraints on the order in which he should study these topics.
    Also, coach Fegla told him that when he studies topic x on the kth day (1 ≤ k ≤ n), his level will
    increase by k*Wx, where Wx is a weight for topic x, representing how hard it is.
    Given the list of topics, the weight of each topic, and the list of constrains, can you tell Montaser
    what is the maximum level he can reach in these n days? He is currently at level 0 L.


    Input
    The first line of input contains one integer T representing the number of test cases (1 ≤ T ≤ 128).
    The first line of each test case contains two integers: n and m (1 ≤ n ≤ 18).
    The next n lines, each contains the title of one of the topics followed by a space, then an integer
    W that represents the weight of this topic (1 ≤ W ≤ 100).
    The next m lines are of the form: Topic 1 --> Topic 2, which means that Topic 1 must be studied
    before Topic 2.
    Titles contain only English letters and spaces (no more than 40 characters).
    Test cases are separated by a blank line.


    Output
    For each test case, print the maximum level that Montaser can reach.


    Sample Input 
    1
    3 2
    Implementation 3
    Dynamic Programming 10
    Greedy 7
    Greedy --> Dynamic Programming
    Implementation --> Dynamic
    Programming

    Sample Output
    47

    题意:

      就是一个人要在n天学完n门课程,每天学习一门,在第i天学习第w[i]门课程他的姿势水平会增加i * w[i],然后这些课程有先后顺序,类似于拓扑排序的

    顺序,比如:a -> b, c -> b, c -> a就表示学习a之前要先学习c,学习b之前要先学习a和c,求他能达到的最高的姿势水平。

    思路:

      输入比较烦人,考虑到n只有18,很容易想到状态压缩,用dp[i]表示状态为i的时候能达到的最高姿势水平,那么dp[i]的值就可以通过枚举状态i的为1的位来得到当前的值

    比如dp[010011(2)] = max(dp[000011(2)] + 3(day) * w[4], dp[010001(2) + 3(day) * w[1], dp[010010(2)] + 3(day) * w[0])来得到。复杂度为

    T*n*logn但是T比较大 满状态的话复杂度是128*18*2^18 = 6e8,很容易被卡常。所以做个优化,就是因为不是没个状态都是可以的,因为要按照拓扑排序的

    顺序,所以我们在转移方程的时候把能够存在的状态给标记一下,这样就有很多状态不是o(n)而是o(1)了。

    代码:

    /** @xigua */
    #include<cstdio>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<cstring>
    #include<queue>
    #include<set>
    #include<string>
    #include<map>
    #include<climits>
    #define PI acos(-1)
    using namespace std;
    typedef long long ll;
    typedef double db;
    const int maxn = 1e2 + 5;
    const int mod = 1e9 + 7;
    const int INF = 1e8 + 5;
    const ll inf = 1e15 + 5;
    const db eps = 1e-9;
    int w[maxn], dp[1<<20];
    map<string, int> mp;
    int n, m, pre[25];
    
    void solve() {
        mp.clear();
        cin >> n >> m; cin.get();
        for (int k = 0; k < n; k++) {
            string s, name; int xx = 0;
            getline(cin, s); int flag = 1;
            for (int i = 0; i < s.size(); i++) {
                if (flag && s[i+1] >= '0' && s[i+1] <= '9') {
                    flag = 0; continue;
                }
                if (flag) name += s[i];
                if (!flag) xx = xx * 10 + s[i] - '0';
            }
            mp[name] = k; w[k] = xx;
        }
        memset(pre, 0, sizeof(pre));
        for (int i = 1; i <= m; i++) {
            string s, xx, hh;
            getline(cin, s); int flag = 0;
            for (int j = 0; j < s.size(); j++) {
                if (s[j+1] == '-') {
                    flag = 1; continue;
                }
                if (flag == 1 && s[j] == ' ') {
                    flag = 2; continue;
                }
                if (flag == 0) xx += s[j];
                if (flag == 2) hh += s[j];
            }
           pre[mp[hh]] |= (1 << mp[xx]); //如果要学习第mp[hh]课程的话要先学习mp[xx]课程
        }
        for (int i = 1; i < (1 << n); i++)
            dp[i] = -INF;
        dp[0] = 0;
        bool can[1<<19] = {0}; can[0] = 1;
        for (int i = 0; i < (1 << n); i++) {
            if (!can[i]) continue;  //不存在当前状态就跳过
            int num = 0;
            for (int j = 0; j < n; j++) {
                num += ((i >> j) & 1);
            }
            for (int j = 0; j < n; j++) {
                int xx = i | (1<<j);
                if (xx != i) {
                    if ((i & pre[j]) != pre[j]) continue; //状态i中是否包括了要学习课程j的所以课程
                    can[xx] = true;
                    dp[xx] = max(dp[xx], dp[i] + (num+1) * w[j]);
                }
            }
        }
        cout << dp[(1<<n) - 1] << endl;
    }
    
    int main() {
        //cin.sync_with_stdio(false);
        //freopen("isharp.in", "r", stdin);
        //freopen("isharp.out", "w", stdout);
        int t = 1; cin >> t;
        
        while (t--) {
            solve();
        }
        return 0;
    }
    /*
    1
    3 2
    Implementation 3
    Dynamic Programming 10
    Greedy 7
    Greedy --> Dynamic Programming
    Implementation --> Dynamic Programming
    */
    

      

  • 相关阅读:
    制作keil5的pack
    【转】链接脚本(1)
    mongodb数据到MySQL数据库 的迁移步骤
    mongo副本集设置主库权重,永远为主
    mongodb副本集的从库永久性设置setSlaveOk
    Ubuntu系统查看mongo得慢日志,及一些操作
    Ubuntu系统下手动释放内存
    linux下面得小数计算
    Syncthing搭建
    ubuntu搭建ftp服务器
  • 原文地址:https://www.cnblogs.com/ost-xg/p/6394976.html
Copyright © 2011-2022 走看看