题解
题目大意 给你n个问题 要求每分钟解决一个问题 且不能中断 如果中断当前得分为最终得分 每个问题的得分为 解决时间*a[i] + b[i] 有的问题需要先完成某些问题才能做
使用状压DP 用二进制压缩为2^20个状态 从小到达暴力枚举每个状态 每个状态检测是否合法 是否满足转移条件 过程每次取最大
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 21;
int a[MAXN], b[MAXN], s[MAXN], n;
ll d[1 << MAXN]; //解决问题状态为i的情况下最高得分
int btcnt(int x)
{
int cnt = 0;
while (x)
{
if (x & 1)
cnt++;
x >>= 1;
}
return cnt;
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
cin >> n;
for (int i = 0; i < n; ++i) //将节点改为0~n-1 减少状态范围
{
int t;
scanf("%d%d%d", &a[i], &b[i], &t);
for (int j = 0; j < t; ++j)
{
int p;
scanf("%d", &p);
s[i] |= 1 << p - 1;
}
}
memset(d, -1, sizeof(d));
d[0] = 0; //一项都没有为0
ll ans = 0, mx = (1 << n) - 1; //mx状态最大值
for (int i = 1; i <= mx; ++i) //枚举全部状态
{
for (int j = 0; j < n; ++j) //当前项
if ((i & 1 << j) && ~d[i & ~(1 << j)] && (i & s[j]) == s[j]) //包含当前项 不包含当前项的状态已经处理 包含当前项所有前置
{
d[i] = max(d[i], d[i & ~(1 << j)] + btcnt(i) * a[j] + b[j]);
ans = max(ans, d[i]);
}
}
cout << ans << endl;
return 0;
}