CF RCC 2014 Warmup (Div. 2) D. Cunning Gena

来源:互联网 发布:学术美国 知乎 编辑:程序博客网 时间:2024/05/17 23:08

LINK

题意 : 一个人要完成m道题目, 他不会,只能去求助她的n个朋友,每个朋友 可以完成mi道题目,需要报酬xi,(拿到报酬后把他会的题目可以全部完成)。
同时 每个朋友 去做题目 需要这个人的电脑 有ki个monitor, monitor价值都为b。(即最终要有monitor的个数为 她选择的朋友中的ki的最大值。)
如何选择 使得 总的花费最少,做完所有的题目。
m很小 (20), 想到了状态压缩dp, 没有monitor这个东西的话,就是很裸的 状态压缩dp。
我们可以 把n个朋友按照,所需monitor的数量从大到小排序,
dp[i][j]表示从1~ith朋友中选择 达到j这个状态,最小的花费(不包括monitor),dp[i][j]=min(dp[i][j],dp[i-1][ k| sta[t]]+x[t]) 最终结果为ans=min(ans,dp[i][(1<<m)-1]+b*k[i]);

这样表示的话 会MLE,考虑到每个状态dp[i][]只会和dp[i-1][]有关, 所以可以用滚动数组 就可以A掉了。

进一步优化的话,可以搞成一维,类似背包,状态转移是逆序遍历就可以了。

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<vector>#include<cmath>#include<queue>#include<map>#include<set>using namespace std;#define INF 2e18typedef __int64 LL;#define N 105#define M 20LL n,m,b,dp[1<<M];struct node{LL x,k,m,save;}num[N];int cmp(node x,node y){return x.k<y.k;}int main(){#ifndef ONLINE_JUDGE    freopen ("in.txt" , "r" , stdin);#endifscanf("%I64d%I64d%I64d",&n,&m,&b);LL tmp;for(int i=1;i<=n;i++){scanf("%I64d%I64d%I64d",&num[i].x,&num[i].k,&num[i].m);num[i].save=0;for(int j=1;j<=num[i].m;j++){scanf("%I64d",&tmp); num[i].save|=(1<<(tmp-1));}}sort(num+1,num+1+n,cmp);for(int i=1;i<(1<<m);i++) dp[i]=INF;dp[0]=0;LL ans=INF;for(int i=1;i<=n;i++){for(int j=(1<<m)-1;j>=0;j--){int next=j|num[i].save;dp[next]=min(dp[next],dp[j]+num[i].x);}ans=min(ans,dp[(1<<m)-1]+num[i].k*b);}if(ans>=INF) printf("-1\n");else printf("%I64d\n",ans);    return 0;}


0 0