题目
n个问题,每个问题有ai,bi
如果第t秒解决就会得到t*ai+bi的分数
有一个si,代表前驱的数量,
以下si个数,
p1,p2,…,psi
代表解决了这些问题,才能解决该问题
可以不做完所有问题,
问最后怎么使分数最大
n<=20
思路来源
https://blog.youkuaiyun.com/u011620711/article/details/82315621
题解
可以去掉某个状态的1,看看补这个1是否合法,
即前驱都在剩下的1里
即枚举哪个1最后加入
也可以枚举向当前状态里加入一个1,
看这个1的所有前驱是否都在当前状态里
剩下的就是下标的对应啦
这里用到了位运算,
哪些是前驱,哪处就对应或上一个1
和传统写法写的不太一样哈……
不过个人感觉更好理解……
补总是比删好理解一些嘛……
代码
#include<iostream>
#include<cstdio>
#include<cmath>
typedef long long ll;
using namespace std;
//用位运算处理必备前驱
ll dp[1<<21],pre[21],a[21],b[21],ans;
int n;
int main()
{
scanf("%d",&n);
for(int i=0;i<n;++i)
{
scanf("%lld%lld",&a[i],&b[i]);
int num;
scanf("%d",&num);
for(int j=0;j<num;++j)
{
int pos;
scanf("%d",&pos);
pos--;
pre[i]|=(1<<pos);
}
}
for(int i=0;i<(1<<n);++i)
{
if(i&&!dp[i])continue;//都没有状态转移到该状态,说明状态非法
int t=__builtin_popcount(i);//已经过去了t秒,做了t个题,该t+1秒了
for(int j=0;j<n;++j)
{
if((pre[j]&i)!=pre[j])continue;//pre[j]含于i才可以 pre[j]|i==i是其等价写法
if(!(i&(1<<j)))//没有j 加上j这个状态
{
dp[i|(1<<j)]=max(dp[i|(1<<j)],dp[i]+(t+1)*a[j]+b[j]);
ans=max(ans,dp[i|(1<<j)]);
}
}
//printf("%d:%lld\n",i,dp[i]);
}
printf("%lld\n",ans);
return 0;
}