E.AC Challenge
题目链接:https://nanti.jisuanke.com/t/30994
题意:你有n个题要去做,你其实都会做但是要求是先做完某些题你才能做这道,每道题做后得分是第n次做题*a[i]+b[i],问你最后最大能得多少分
思路:第一开始去向网络流,但仔细想想他和时间还有关系,由于数据量只有20,果断去想DP,我们用二进制去存某些题做过没有,dp[i],i是二进制表示法确定做了那些题,dp[i]表示做这些题最大得多少分,我们用二进制去存好题与题得关系,我们用lowbit去数他完成了几道题,然后去返回这回是该做第几道,那么就简单得去状态压缩就好了,每次看i是否满足我们想做得当前题,如果满足我们就去把他得dp[i+1<<j]更新即可
状态转移方程是dp[i+(1<<j)]=max(dp[i+(1<<j)],dp[i]+做j题得到得分数);
当时又个毛病就是用define 去定义long long 之后我开数组得时候用了maxn+5 使得左移符号运算优先级低于+,导致内存超限,各种后悔
下面上代码
#include<bits/stdc++.h>
#define maxn 1<<20
#define ll long long
using namespace std;
ll dp[maxn];
int a[25],b[25],d[25];
int su(int x)
{
int cnt=0;
while(x){
x-=x&-x;
cnt++;
}
return cnt+1;
}
int main()
{
int n,x,y;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d%d%d",&a[i],&b[i],&x);
while(x--){
scanf("%d",&y);
d[i]+=1<<(y-1);
}
//cout<<i<<endl;
}
ll now=(1<<n)-1;
for(int i=0;i<=now;i++){
if(dp[i]==0&&i!=0)continue;
for(int j=0;j<n;j++){
if((i&(1<<j))==0&&(i&d[j])==d[j]){
dp[i+(1<<j)]=max(dp[i+(1<<j)],dp[i]+su(i)*a[j]+b[j]);
}
}
}
ll ans=0;
for(int i=0;i<=now;i++)
ans=max(dp[i],ans);
printf("%lld\n",ans);
return 0;
}