zoj 3812 We Need Medicine(dp)
来源:互联网 发布:变声器的软件 编辑:程序博客网 时间:2024/05/12 13:44
题意:给出n个物品,每个物品有两种属性Wi,Ti,有q组查询,每组查询要求在n个物品中选出一些,并使得两个属性的和为Mi,Si。
思路:刚开始看感觉是神题,后来仔细想了想,其实本质上就是个背包。最裸着写的话,那么就是dp[i][j][k]表示使用前i个物品,是否可以凑出第一个属性j,第二个属性k,要输出方案的话记录一下路径就可以了。一开始这么写了一发,加了一些乱七八糟的优化,还是会T。虽然这题时限还算宽,但这么写复杂度还是太高了。考虑到第一个属性最多只有50,那么可以用一个二进制数来表示是否能凑出第一个属性的情况,即:第i位为1表示可以凑出i。使用这种方法的好处是对于物品i可以直接算出第一种属性的组合情况,枚举一下新增的位,更新一下结果就行了。
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<stack>#include<set>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-8#define pi acos(-1.0)using namespace std;typedef long long ll;typedef unsigned long long ull;const int maxn = 400 + 10;const int M = 51;short ans[200010][52];ull f[200010];int W[maxn],T[maxn];map<ull,int>mp;int main(){// freopen("in.txt","r",stdin);// freopen("out.txt","w",stdout); for(int i = 1;i <= M + 1;++i) mp[1LL<<(i-1LL)] = i; int t,n,q; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&q); memset(ans,0,sizeof(ans)); memset(f,0,sizeof(f)); f[0] = 1; ull v,x; for(int i = 1;i <= n;++i) { scanf("%d%d",&W[i],&T[i]); for(int j = 200000;j >= T[i];--j) { v = f[j]; //f[j]表示第二个属性为j时,能够凑出的第一个属性的集合,用一个二进制数表示,第i位为1表示可以凑出这个数 f[j] |= (f[j - T[i]]<<W[i]) & ((1LL<<M+1) - 1); //计算使用当前物品能够得到的新的集合,在集合f[j - T[i]]添加W[i]的物品, //即原来能得到的每个值加上W[i],等价于将其左移W[i]位 for(ull k = v ^ f[j];k ; k &= k-1) //枚举新增加的集合 { x = (k ^ (k - 1)) & k; ans[j][mp[x] - 1] = i; //将新增的位置更新,记录是使用了哪个物品达到的这个状态 } } } int m,s,p; for(int i = 0;i < q;++i) { scanf("%d%d",&m,&s); if(!ans[s][m]) puts("No solution!"); else { printf("%d",ans[s][m]); p = ans[s][m]; m -= W[p]; s -= T[p]; while(m) { p = ans[s][m]; printf(" %d",p); m -= W[p]; s -= T[p]; } puts(""); } } } return 0;}
0 0
- [ZOJ 3812 We Need Medicine] DP
- zoj 3812 We Need Medicine(dp)
- 【DP】 ZOJ 3812 We Need Medicine
- 【ZOJ】3812 We Need Medicine
- ZOJ 3812 We Need Medicine
- zoj 3812 We Need Medicine
- ZOJ 3812 We Need Medicine 状压DP 回溯
- zoj 3812 We Need Medicine(01背包)
- 背包 ZOJ 3812 We Need Medicine
- ZOJ 3812 We Need Medicine(dp,状态压缩,2014牡丹江网络赛D题)
- zoj 3812 We Need Medicine (dp 位优化 巧妙记录路径)
- ZOJ 3812 We Need Medicine 01背包+位优化
- ZOJ3812--We need Medicine
- ZOJ 3812 We Need Medicine(牡丹江网络赛D题)
- zoj3812 We Need Medicine 背包+位优化
- 2014 Mudanjiang Online Contest Problem D We Need Medicine
- We Need Medicine zoj3812 The 2014 ACM-ICPC Asia Mudanjiang Regional
- Why we need StackOverFlow?
- Ubuntu Chromium flash 安装方法
- 剑指Offer:面试题23 从上往下打印二叉树
- HDU 3700 Cat
- Navicat使用技巧
- 剑指Offer:面试题24 二叉搜索树的后序遍历序列
- zoj 3812 We Need Medicine(dp)
- [leetcode] Maximal Rectangle
- Java enum 枚举还可以这么用
- 剑指Offer:面试题25 二叉树中和为某一值的路径
- 常见排序总结
- CCLabelTTF、CCLabelAtlas和CCLabelBMFont的区别
- 剑指Offer:面试题26 复杂链表的复制
- UltimateAndroid快速开发框架简介与教程(也是一套Android快速开发的教程)
- LeetCode: Reverse Words in a String