版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yz467796454/article/details/82498995
题目链接:https://nanti.jisuanke.com/t/30994
样例输入1
5
5 6 0
4 5 1 1
3 4 1 2
2 3 1 3
1 2 1 4
样例输出1
55
样例输入2
1
-100 0 0
样例输出2
0
题意:n个题目,做每一个题目的得分是t*ai+bi,做某一题前必须先做完规定的题,求最大的得分
思路:n只有20,状压dp,dp[i]表示,i这个状态下的最大得分
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<set>
using namespace std;
typedef long long ll;
struct node{
ll a,b;
int s;
int p[50];
}q[50];
ll dp[1<<20];//第i个状态的最大得分
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld%lld%d",&q[i].a,&q[i].b,&q[i].s);
for(int j=1;j<=q[i].s;j++){
scanf("%d",&q[i].p[j]);
}
}
memset(dp,0,sizeof(dp));
for(int i=0;i<(1<<n);i++){//枚举每个状态
int flag=1;
for(int j=1;j<=n;j++){
if(!((1<<(j-1))&i))continue;//i这个状态下,j这一题没有做
for(int k=1;k<=q[j].s;k++){//判断做j题前必做的题是否做了
if(!((1<<(q[j].p[k]-1))&i)){
flag=0;break;
}
}
if(!flag)break;
}
if(!flag)continue;//存在某一已做的题,做这一题前的必做的题还没有做,说明这个状态不存在
int x=i;
int t=0;//1的个数,即这个状态已经做了几题
while(x){
if(x&1)t++;
x>>=1;
}
for(int j=1;j<=n;j++){
if(!((1<<(j-1))&i))continue;
dp[i]=max(dp[i],dp[(1<<(j-1))^i]+t*q[j].a+q[j].b);//j这个问题在t这个时间做
// (1<<(j-1))^i表示在i这个状态中,去掉j这个题的状态
}
}
printf("%lld\n",dp[(1<<n)-1]);
return 0;
}