hrbust 1663 水果【状压dp】【原创1000篇纪念!!!】
来源:互联网 发布:安居客网络门店管理 编辑:程序博客网 时间:2024/06/16 08:28
![](http://acm.hrbust.edu.cn/Public/images/star-solid.png)
![](http://acm.hrbust.edu.cn/Public/images/star-solid.png)
![](http://acm.hrbust.edu.cn/Public/images/star-solid.png)
![](http://acm.hrbust.edu.cn/Public/images/star-solid.png)
![](http://acm.hrbust.edu.cn/Public/images/star-half2.png)
吃水果可以补充维生素A、B、C、D、E….
小z在月初买了N种水果,每种水果各买了一个。每种水果都有一个初始的新鲜度Ti,每过一天就会减少Di,即第二天的新鲜度为Ti-Di,第3天为Ti-Di*2,依次类推。一旦新鲜度变为负数,那个水果就不能吃了。
小z每天都按照一种水果的搭配来吃水果,这些搭配不是随意的,而是只能从事先计划好的M中搭配中选择一种。每种搭配由Ki个水果组成,一种搭配的营养值是由Ki个水果当天的新鲜度之和再加上一个额外的搭配营养值Ei组成。需要注意的是当某种搭配中的一个水果不能吃的时候,这个搭配就不能用了;而且,有可能存在两个搭配里面的组合是一样的,但是额外的搭配营养值不同。
为了能够获得更多的营养,小z希望找出一种最优的方案,你能帮助他计算出最优方案下一共获得的营养值么?
多组测试数据。
每组数据第一行输入一个整数N表示水果的种数,按1~N编号。(0<N<15)
接下来的N行,每行两个整数Ti,(Ti<100)和Di(Di<100),表示第i种水果的初始新鲜度和每天的递减值。
第N+2行为一个正整数M,表示搭配的种数。(0<M<20)
接下来的M行,每行先是一个正整数Ki,表示组成这个搭配的水果的数目,然后是一个非负整数Ei(Ei<100),表示这种搭配额外的营养值,最后是Ki个整数,每个整数为水果的编号。
Output对于每组数据输出一行,包含一个整数,表示最大的营养值。
Sample Input23 1
4 2
2
1 1 1
1 1 2
2
3 1
4 2
3
1 1 1
1 1 2
2 2 1 2
9
思路:
1、观察到数据范围N,M都在20以内,那么考虑状压dp,其中又包含一个第几天到底吃第几种搭配的问题,那么我们设定dp【i】【j】表示第i天,吃了状态为j的水果的时候的最多营养值收获。(例如当前j=5,5=101(二进制),其表示我们现在吃了第一种和第三种食物,第二种食物并没有吃)
2、对应我们首先进行各项预处理:
①设定tmp【i】,表示第i种搭配的食物需要吃的水果的状态。
②设定dead【i】,表示第i天坏掉了的水果的状态。
3、然后我们考虑其状态转移方程:
①dp【i】【j】=max(dp【i】【j】,dp【i-1】【q】+val【k】+cal(i,k));
表示今天的状态我们从昨天转移过来。
②其中k表示第i天吃的搭配编号,val【k】表示第k种搭配获得的营养值,cal(i,k)表示所有食物新鲜值的总和。
③那么我们第一层for枚举i,第二层for枚举状态j,第三层for枚举k;表示我们第i天要吃第k种搭配的食物,那么我们接下来需要判断当前状态j是否可行。
④那么我们对应判断这一天的时候,第k种搭配中的食物有没有坏掉的,如果有坏掉的,那么不进行状态转移,接下来判断一下状态j是否包含第k种搭配中的所有食物。如果满足,那么当前dp【i】【j】就是一个可行状态。那么对应q=j-tmp【k】,表示上一天我没有吃第k种搭配的食物,那么我们接下来直接进行状态转移即可。
4、那么其解就在dp【i】【j】(0<=i<m&&0<=j<(1<<n))中,我们这里暴力维护一波最大值即可。
总时间复杂度估计为:O(N*M*(1<<N));
Ac代码:
#include<stdio.h>#include<iostream>#include<string.h>using namespace std;struct node{ int ti,di;}a[50];int n,m;int dp[24][(1<<16)];int dead[50];int val[50];int tmp[50];int cal(int day,int k){ int sum=0; for(int i=0;i<n;i++) { if(((1<<i)&tmp[k])!=0) { sum+=a[i].ti-a[i].di*day; } } return sum;}int main(){ while(~scanf("%d",&n)) { memset(dead,0,sizeof(dead)); memset(dp,-1,sizeof(dp)); memset(val,0,sizeof(val)); memset(tmp,0,sizeof(tmp)); for(int i=0;i<n;i++) { scanf("%d%d",&a[i].ti,&a[i].di); } scanf("%d",&m); for(int i=0;i<m;i++) { int kk; scanf("%d%d",&kk,&val[i]); while(kk--) { int x; scanf("%d",&x); x--; tmp[i]+=(1<<x); } } for(int i=0;i<m;i++) { for(int j=0;j<n;j++) { if(a[j].ti-a[j].di*i<0) { dead[i]+=(1<<j); } } } for(int i=0;i<m;i++) { int j=tmp[i]; dp[0][j]=max(val[i]+cal(0,i),dp[0][j]); } for(int i=1;i<m;i++)//第i天 { for(int j=0;j<(1<<n);j++)//这一天的状态 { for(int k=0;k<m;k++)//这一天想要吃第k种搭配的食物 { if((j&tmp[k])==tmp[k]) { if((tmp[k]&dead[i])==0)//这一天想要吃的食物中没有坏的 { int q=j-tmp[k]; if(dp[i-1][q]==-1)continue; dp[i][j]=max(dp[i-1][q]+val[k]+cal(i,k),dp[i][j]); } } } } } int output=0; for(int i=0;i<m;i++) { for(int j=0;j<(1<<n);j++) { output=max(output,dp[i][j]); } } printf("%d\n",output); }}
- hrbust 1663 水果【状压dp】【原创1000篇纪念!!!】
- hrbust 1000 A + B Problem【600篇原创纪念】
- 【hrbust700纪念】Hrbust 1847 擦除字符串【状压dp+Dfs枚举可行状态+剪枝】好题
- hrbust 1525 水神【纪念搜索题解100篇】【Bfs】
- Hrbust 2051 Mountain Subsequences【dp+思维】【哈理工OJ 800题纪念】
- hrbust 1843 方格取数【状压dp】
- hrbust 1473 教主的遗产【状压dp】
- hrbust 2141 Watch Dogs【状压dp】
- HRBUST 2141 Watch Dogs [状压DP]
- Hrbust 1089 再就业(状压DP)
- 纪念第100篇原创博客
- hrbust 1186 简单DP
- hrbust 1705 最高分【Dp】
- Hrbust 1327 合唱【dp】
- Hrbust 1837 Dream【dp】
- Hrbust 1788 Chocolate【Dp】
- hrbust/哈理工oj 2280 去吧,皮卡秋【状压dp】
- hrbust/哈理工oj 1809 再就业【状压dp】
- 原生JS实现获取随机验证码
- python 元组
- JAVA之servlet
- 欢迎使用CSDN-markdown编辑器
- Linux环境下安装RocketMQ(MetaQ)
- hrbust 1663 水果【状压dp】【原创1000篇纪念!!!】
- RxJava学习之基本使用
- 汇编语言之寄存器(CPU工作原理)
- centos 7 epel源 安装jq
- Python模拟post提交表单数据 ——某二手车网站回拨电话的分析与利用
- BSOJ2909 Vijos 1474 南邮OJ1573 雷曼兔
- linux中断子系统 - irq_desc的创建
- C++学习(五)——string使用注意事项(一)
- 数据结构实验之二叉树的建立与遍历