/**
题意:n道题,每道题有先修题,每题用时1,得到价值为 a*t+b,问最大快乐值
分析:状压dp,状态是已经上的课
*/
#include <bits/stdc++.h>
#define T__ int T;scanf("%d",&T);while(T--)
using namespace std;
typedef long long LL;
const int maxn=20+5;
const int INF=0x3f3f3f3f;
LL dp[1<<21],ans=0;
int a[maxn],b[maxn],s,pre[maxn];
int main()
{
#ifdef _WY
freopen("data.in","r",stdin);
#endif // _WY
int n,p;scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i],&b[i],&s);
while(s--){
scanf("%d",&p);
pre[i]|=(1<<(p-1));
}
}
ans=0;
memset(dp,129,sizeof dp);dp[0]=0;
for(int s=0;s<(1<<n);++s){
for(int i=1;i<=n;++i){
if((1<<(i-1))&s) continue;
//可转移
if((pre[i]&s)==pre[i]){
int ss=s|(1<<(i-1));
dp[ss]=max(dp[ss],dp[s]+__builtin_popcount(ss)*1ll*a[i]+b[i]);
ans=max(ans,dp[ss]);
}
}
}
printf("%lld\n",ans);
return 0;
}
/**
预处理每个状态有多少个1
for(ll i=1;i<(1<<n);i++)
num[i]=num[i&(i-1)]+1;
**/
/**
for(ll s=0;s<(1<<n);s++){枚举状态
for(ll i=1;i<=n;i++){对每个课程
if((1<<(i-1))&s) continue;如果该课程在状态里那么退出
if((sta[i]&s)==sta[i]){否则呢,如果该状态符合课程的先行课要求
ll st=s|(1<<(i-1)); 那么更新状态加上这个课的dp值
dp[st]=max(dp[st],dp[s]+num[st]*a[i]+b[i]);
ans=max(ans,dp[st]);
}
}
}
**/
南京网络赛 E AC Challenge 状压dp
最新推荐文章于 2025-03-11 11:28:52 发布