Codeforces Gym 100676G Training Camp 状压dp

http://codeforces.com/gym/100676

题目大意是告诉你要修n门课,每门课有一个权值w[i], 在第k天修该课程讲获得k*w[i]的学习点数,给出了课程与先修课程的关系,要修该课程必须修完先修课程。问最多能学到多少点数。

非常简单的一道状压dp(一开始我还误导队友写成两维的去了 T^T);

dp[s] : s 的二进制存放的是已经选择的课程,在该状态下的能获得的最大的点数。

这时如果再学一门课程k,将转移到状态ss (s | (1 << k) ) ,能否转移需要判断合法性。这里把课程k的先修课程存在一个int里面,S & prev[k] == prev[k]则表示可以选项k课程。dp数组一开始需要初始化成无穷小。最后只要找dp[(1 << n ) - 1] 。

/*输入真恶心*/

 

#include <map>

#include <cstdio>

#include <vector>

#include <cstring>

#include <iostream>

#include <algorithm>



using namespace std;



const int INF = 999999999;



int n,m;



map<string, int> Map;



int w[20];



int prve[20];



void read() {

    cin >> n >> m;getchar();



    char _a[101];

    string _s, _t;

    int _num;

    int _len;

    for (int i=0; i<n; i++) {

        gets(_a);



        _len = strlen(_a);



        int k = 0;

        while(_a[k] < '0' || _a[k] > '9') k++;



        _a[k-1] = '\0';

        _s = (string) _a;



        _num = 0;

        while (k < _len && _a[k] >= '0' && _a[k] <= '9') {

            _num = _num * 10 + _a[k] - '0';

            k++;

        }



        Map[_s] = i;

        w[i] = _num;

    }



    for (int i=0; i<m; i++) {

        gets(_a);



        int k = 0;

        while (_a[k] != '-') k++;



        _a[k-1] = '\0';



        _s = (string) _a;

        _t = (string) (_a + k + 4);



        prve[Map[_t]] |= (1 << Map[_s]);

    }

}





int dp[(1<<18)+5];



void DP () {



    for (int s=0; s<(1<<n); s++) {



        int _num = 0;



        for (int i=0; i<n; i++) {

            _num += ((s >> i) & 1);

        }



        for (int i=0; i<n; i++) {

            int ss = s | (1 << i);



            if (((s >> i & 1) != 0) || ((s & prve[i]) != prve[i])) continue;



            if (_num == 0 && prve[i] == 0) {

                dp[ss] = w[i];

                continue;

            }



            dp[ss] = max(dp[ss], dp[s] + (_num + 1) * w[i]);

        }

    }



    cout << dp[(1<<n)-1] << endl;

}



void init() {

    Map.clear();

    fill(dp, dp + (1 << 18), -INF);

    memset(prve, 0, sizeof(prve));

}



int main () {

    int t;

    cin >> t ;

    while (t--) {

        init();

        read();

        DP();

    }

    return 0;

}
View Code

 

你可能感兴趣的:(codeforces)