版权声明: https://blog.csdn.net/yyy_3y/article/details/82313990
题意:
1)n个题目,每个题目的权值为a
,b
,和s个先决条件(也就是说要先做出这几题才能做这道题),如果在T分钟做出来这题,收益就是a
*T+a
问你能获得的最大收益。
思路:
1)一共就20题,很有状压的感觉。
2)主要思路就是对于当前的一个状态,如果当前这道题没有做过并且这道题的的先决条件都已做过,那么就更新,dp[i]就表示这个状态所能获得的最大收益。
3)优化方面的话,①可以预处理出每个状态有多少个1(也就是做过的题数)②对于每道题的先决条件用一个二进制存,比较的时候用 | 判断下就行。
4)复杂度是2
*20,不优化的话多一个20,4e8,听说也能过~(现场的时候4
e8并不敢写qwq,想到2e7才敢的qwq。)
#include<bits/stdc++.h>
#define debug(a) cout << #a << " " << a << endl
#define lnn putchar('\n')
#define see putchar(' ')
#define LL long long
#define ull unsigned long long
#define PI acos(-1.0)
#define eps 1e-6
const int N=2e5+7;
const LL inf=1e18;
using namespace std;
LL f[30],dp[1<<21],cnt[1<<21];
LL a[30],b[30];
void init()
{
for(int i=0;i<(1<<21);i++){
dp[i]=-inf;
int tmp=i;
int ans=0;
while(tmp){
if(tmp%2)ans++;
tmp/=2;
}
cnt[i]=ans;
}
}
int main ()
{
//yyy_3y
//freopen("1.in","r",stdin);
init();
int n; scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld",&a[i],&b[i]);
int s; scanf("%d",&s);
for(int j=1;j<=s;j++){
LL x; scanf("%lld",&x);
f[i]=(f[i]|(1<<(x-1)));
}
}
dp[0]=0;
for(int i=0;i<(1<<n);i++){
for(int j=1;j<=n;j++){
if( (i|f[j])>i ) continue;
if((i>>(j-1))&1) continue;
dp[i+(1<<(j-1))]=max(dp[i]+a[j]*(cnt[i]+1)+b[j],dp[i+(1<<(j-1))]);
}
}
LL ans=0;
for(int i=0;i<(1<<n);i++){
ans=max(ans,dp[i]);
}
printf("%lld\n",ans);
return 0;
}