鏈接: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;
}