原题地址:http://codeforces.com/problemset/problem/417/D
题意:
Gena 为了解决m个问题,请他的朋友们帮忙,其中第i个朋友可以解决某mi个问题,需要花费xi卢布,并且要求安装至少ki个显示器,每个显示器需要b卢布。
问解决所有问题需要多少多少卢布
题解
考虑问题数目很小,可以状压DP。
dp[S]表示当前状态的最优解,通过位运算进行转移。
考虑|没有逆运算,所以只能正推更新。
首先把朋友按照k排序,避免k的干扰。
dp[][0]和dp[][1]分别表示考虑显示器花费和不考虑显示器花费的最小值
#include<bits/stdc++.h> #define clr(x,y) memset((x),(y),sizeof(x)) using namespace std; typedef long long LL; const int maxn=(1<<20); const LL inf=2e18; struct Node { LL x,k,m; int S; bool operator < (const Node& a) const { return k<a.k; } }; LL dp[maxn+5][2]; Node f[105]; LL n,m,b; int main(void) { #ifdef ex freopen ("../in.txt","r",stdin); //freopen ("../out.txt","w",stdout); #endif scanf("%I64d%I64d%I64d",&n,&m,&b); for (int i=1;i<=n;++i) { scanf("%I64d%I64d%I64d",&f[i].x,&f[i].k,&f[i].m); int q; for (int j=1;j<=f[i].m;++j) { scanf("%d",&q); --q; f[i].S=f[i].S|(1<<q); } } sort(f+1,f+1+n); int S=(1<<m)-1; dp[0][0]=0; dp[0][1]=0; for (int i=1;i<=S;++i) for (int j=0;j<=1;++j) dp[i][j]=inf; for (int i=1;i<=n;++i) { //printf("%d\n",f[i].S); for (int j=S;j>=0;--j) { if (dp[j][0]==inf) continue; int tS=j|f[i].S; dp[tS][0]=min(dp[tS][0],dp[j][0]+f[i].x); dp[tS][1]=min(dp[tS][1],dp[j][0]+f[i].x+f[i].k*b); //printf("%d %d %d\n",tS,i,dp[tS][1]); } } if (dp[S][1]==inf) printf("-1\n"); else printf("%I64d\n",dp[S][1]); }