链接:https://ac.nowcoder.com/acm/contest/946/B
来源:牛客网
筱玛爱阅读
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262875K,其他语言525750K
64bit IO Format: %lld
题目描述
筱玛是一个热爱阅读的好筱玛,他最喜欢的事情就是去书店买书啦!
一天,他来到一家有nn本书的书店,筱玛十分快乐,决定把这家店里所有的书全部买下来。
正巧今天店里在搞促销活动,包含若干个促销方案。每个促销方案是由指定的若干本书构成的集合,如果购买了该方案中所有的书,那么其中最便宜的一本书将免费。但是,每本书只能用于一个促销方案。
作为店里的VIP,筱玛会得到nn个价格标签。筱玛可以给每本书挑选一个价格标签,使得每个价格标签和每本书一一对应。
筱玛想要知道,在合理利用所有促销方案的情况下,买下所有书最小要多少钱。
输入描述:
第一行两个数n,mn,m,分别表示书的本数和促销方案的种数。
第二行nn个整数,表示每个价格标签上的标注的价格。
接下来mm行,每行第一个数kk表示该促销方案包含书的数量。接下来kk个数,表示书的编号。
输出描述:
输出一行一个数,表示答案。
示例1
输入
4 2
2 3 2 4
2 2 3
2 2 4
输出
8
备注:
对于100%的数据,1≤n≤15,1≤m≤2n−11≤n≤15,1≤m≤2n−1,所有标签价值之和在intint范围内。
、
子集DP
预处理cnt[i] 为 i 的二进制中1的数目
dp[i]为购买状态为i的书的最大优惠
cost 先排序
每个方案贪心取最大
添加j方案 i^j是原来的方案 加上可选的最大的 cost 更新
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1<<15)+12;
int cost[20];
int num[maxn];
vector<int>v[maxn];
int flag[maxn];
int dp[maxn];
int cnt[maxn];
int main()
{
int n,m,x;
cin>>n>>m;
ll sum=0;
for(int i=1; i<=n; i++)
{
scanf("%d",&cost[i]);
sum+=cost[i];
}
sort(cost+1,cost+n+1,greater<int>());
for(int i=1; i<=m; i++)
{
scanf("%d",&num[i]);
for(int j=1; j<=num[i]; j++)
{
scanf("%d",&x);
v[i].push_back(x);
}
int mi=cost[v[i][0]];
int tp=0;
for(int j=0; j<v[i].size(); j++)
{
mi=min(cost[v[i][j]],mi);
tp|=(1<<(v[i][j]-1));
}
flag[tp]=1;//标记可更新套餐
}
int ma=1<<n;
for(int i=1;i<ma;i++)
cnt[i]=cnt[(i&(i-1))]+1;//求二进制中i中1的位数
ll ans=sum;
for(int i=0; i<ma; i++)
{
int s=i;
for(int j=s;j;j=(j-1)&s)
{
if(flag[j])
{
dp[i]=max(dp[i],dp[i^j]+cost[cnt[i]]);//更新
}
}
ans=min(ans,sum-dp[i]);
}
cout<<ans;
return 0;
}