CF417D Cunning Gena

Gena非常想参加“俄罗斯code cup”的决赛,或是至少得到一件T恤。 但是比赛的题目太复杂了,所以他安排他的n个朋友帮他解决这些问题。

在比赛中会有m道题目提供给参赛者。对于每个朋友,Gena知道他能解决什么问题。 但是Gena的朋友不会无偿的去帮助Gena的, 第i个朋友会因为帮助Gena解决所有他会的问题而向Gena索要x卢布。 并且,只有在Gena的电脑连接到至少k台显示器时,这个朋友才会去帮助Gena写代码。 且每台显示器需要花费b卢布。

Gena很节约用钱,所以他希望尽可能少的花钱去解决所有问题。 请你帮助Gena,告诉他怎样花费最少的钱。 最初,Gena的电脑没有连接任何显示器。

输入格式:

第一行包含三个整数 n , m 和 b ( 1<=n<=100 1<=n<=100 ; 1<=m<=20 1<=m<=20 ; 1<=b<=1e9 1<=b<=1e9) 其中, n代表Gena的总朋友数,m代表问题数,b代表一个显示器的花费

接下来的 2n 行描述每个朋友。 第 2i 和 (2i+1) 行包含第i个朋友的信息。 第 2i 行包含三个整数 xi , ki , mi (1<=xi<=1e9 ; 1<=ki<=1e9 ; 1<=mi<=m )其中,xi表示这个朋友解决题目需要得到的钱,ki表示显示器数量需求,mi表示这个朋友能解决的问题的数目。 第 (2i+1) 行包括mi个不同的正整数—第i个朋友所能解决的问题的编号。 所有的问题按1-m编上了序号。

输出格式:

输出最小花费,如果不能完成所有问题,输出-1

刚开始被降智了。

发现\(m\)很小,可以状压完成的问题情况,然后我们按显示器需求量从小到大排序,那么dp到\(i\)的时候,前\(i\)个朋友需求的显示器量就是第\(i\)个朋友的显示器需求量,所以设\(f_s\)表示当问题解决情况是\(s\)时,不考虑显示器需求所需要的最小费用,可以写出如下转移:

\[f_{s|v_i}=min(f_s+x_i) \]

\[ans=min(f_{2^m-1}+k_i) \]

其中\(v_i\)是第\(i\)个朋友能完成任务的二进制数。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ull unsigned long long 
const int N = 100;
const ull inf = 1e19;
using namespace std;
struct friends
{
    int x,k,m,v;
}a[N + 5];
int n,m,b,g[1 << 20];
ull f[1 << 20],ans;
bool cmp(friends a,friends b)
{
    return a.k < b.k;
}
int main()
{
    scanf("%d%d%d",&n,&m,&b);
    int u;
    for (int i = 1;i <= n;i++)
    {
        scanf("%d%d%d",&a[i].x,&a[i].k,&a[i].m);
        for (int j = 1;j <= a[i].m;j++)
        {
            scanf("%d",&u);
            a[i].v |= 1 << u - 1;
        }
    }
    sort(a + 1,a + n + 1,cmp);
    for (int i = 1;i < (1 << m);i++)
        f[i] = inf;
    ans = inf;
    for (int i = 1;i <= n;i++)
    {
        for (int s = 0;s < (1 << m);s++)
            f[s | a[i].v] = min(f[s | a[i].v],f[s] + a[i].x);
        ans = min(ans,f[(1 << m) - 1] + 1ll * a[i].k * b);
    }
    if (ans == inf)
        cout<<-1<<endl;
    else
        cout<<ans<<endl;
    return 0;
}
posted @ 2020-11-17 08:56  eee_hoho  阅读(115)  评论(0编辑  收藏  举报