南京网络赛 E. AC Challenge【状压DP详解】

题意:n个题目,对于每个题目,在做这个题目之前规定了必须先完成哪些题目,第t秒做的题目i得分是t×ai+bi,每一秒必须且只能做一题,问最终的最大得分是多少?
分析:状压DP。。。
对于枚举每一种状态,是否可以合理的推到下一种状态呢?也就是对于已经做过的题去推下一道该做的题。
如果当前状态有值(被计算过了),那么其他没做过的题就可以被当做接下来要做的那一道,就暴力推下一种状态。这样想是完全合理的,因为对于已经完成的题目去找下一个要做的题目,在这时每一个题目都被遍一次,所有的状态都被考虑到了。
我用了两份代码,思路都是一样,对于已知的题目去找下一道应该做的。
第一份代码:

#pragma GCC optimize ("O3")
#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define met(s) memset(s, 0, sizeof(s))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
template <class T> inline void scan_d(T &ret) {
char c; ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0'), c = getchar();}}
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int MAXN = 21;
LL a[MAXN], b[MAXN];
LL dp[1 << MAXN];
vector<int> G[MAXN];

bool judge(int t, int s) {
    if(dp[t] == -1) return false;
    for(int i = 0; i < G[s].size(); ++i) {
        int u = G[s][i];
        if((t & (1 << u)) == 0) return false;
    }
    return (t & (1 << s)) == 0;
}

LL so(int x) {
    LL cnt = 0;
    while(x) {
        if(x % 2) cnt++;
        x >>= 1;
    }
    return cnt + 1;
}

int main() {
    int n, k, q; scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        scanf("%lld %lld %d", &a[i], &b[i], &q);
        while(q--) {
            scanf("%d", &k);
            G[i].push_back(k - 1);
        }
    }
    memset(dp, -1, sizeof(dp)); dp[0] = 0;
    LL ans = 0; 
    for(int i = 0; i < (1 << n); ++i) {
        for(int j = 0; j < n; ++j) {
            if(!judge(i, j)) continue;
            dp[i + (1 << j)] = max(dp[i + (1 << j)], dp[i] + so(i) * a[j] + b[j]);
            //printf("## %d %lld\n", j, dp[i + (1 << j)]);
            ans = max(dp[i + (1 << j)], ans);
        }
    }
    printf("%lld\n", ans);
    return 0;
}

第二份代码:

#pragma GCC optimize ("O3")
#pragma GCC optimize ("O2")
#include <bits/stdc++.h>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define met(s) memset(s, 0, sizeof(s))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
template <class T> inline void scan_d(T &ret) {
char c; ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0'), c = getchar();}}
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int MAXN = 21;
LL a[MAXN], b[MAXN];
LL dp[1 << MAXN];
vector<int> G[MAXN];

bool judge(int t, int s) {
    if((t & (1 << s)) == 0 || dp[t ^ (1 << s)] == -1) return false;
    for(int i = 0; i < G[s].size(); ++i) {
        int u = G[s][i];
        if((t & (1 << u)) == 0) return false;
    }
    return true;
}

LL so(int x) {
    LL cnt = 0;
    while(x) {
        if(x % 2) cnt++;
        x >>= 1;
    }
    return cnt;
}

int main() {
    int n, k, q; scanf("%d", &n);
    for(int i = 0; i < n; ++i) {
        scanf("%lld %lld %d", &a[i], &b[i], &q);
        while(q--) {
            scanf("%d", &k);
            G[i].push_back(k - 1);
        }
    }
    memset(dp, -1, sizeof(dp)); dp[0] = 0;
    LL ans = 0; 
    for(int i = 1; i < (1 << n); ++i) {
        for(int j = 0; j < n; ++j) {
            if(!judge(i, j)) continue;
            dp[i] = max(dp[i], dp[i ^ (1 << j)] + so(i) * a[j] + b[j]);
        //  printf("## %d %lld\n", j, dp[i]);
        }
        ans = max(dp[i], ans);
    }
    printf("%lld\n", ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值