CF417D:状态压缩DP

CF417D

题意

  • 一共需要解决m道问题。小伙伴至少需要y台监视器才答应写题目,每台b元。每个人又需要x元的费用。给出每个人可以解决的题目。最少需要多少花费能够解决所有问题。

题解

  • 状态压缩DP。把每个人可以解决的题目给状态压缩一下。
  • 按监视器数量对大家排序。枚举到第i个人,那么编号≤i的人都满足监视器的要求。监视器的费用可以单独考虑。不用dp。
  • dp[i]表示能够解决i道题目的最小花费。初始化为-1,dp[0] = 0。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll const inf = 4e18;
int const N = 105;
int const M = 20;
int n,m,b;
struct Node
{
	ll x,y;
	int s;
	bool operator < (const Node& e)const{
		return y < e.y;
	}
}p[N];
ll dp[(1<<M)+10];    //dp[i]表示解决i道题目的最小花费
ll solve(){ 
	ll ans = inf;
	memset(dp,-1,sizeof(dp));
	dp[0] = 0;
	for(int i=0;i<n;i++){
		for(int j=0;j<(1<<m);j++){
			if(dp[j] == -1)	continue;
			if(dp[j|p[i].s] == -1){
				dp[j|p[i].s] = dp[j] + p[i].x;
			}else dp[j|p[i].s] = min(dp[j|p[i].s],dp[j] + p[i].x);
		}
		if(dp[(1<<m)-1] != -1)
			ans = min(ans,dp[(1<<m)-1] + p[i].y * b); 
	} //如果第i个人参与,且价值比上一次还大,那么取上一次。如果上一次小,取这一次。如果没参与,那么还是上一次的。
	return ans == inf ? -1 : ans;
}
int main(){
	scanf("%d%d%d",&n,&m,&b);
	for(int i=0;i<n;i++){
		int pro;
		scanf("%lld%lld%d",&p[i].x,&p[i].y,&pro);  //x的雇佣金,y台显示器,能够解决pro个问题
		for(int j=1;j<=pro;j++){
			int k;	scanf("%d",&k);
			p[i].s |= 1 << (m - k);
		}
	}
	sort(p,p+n);
	printf("%lld",solve());
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/89060750