题意: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;
}