POJ 1170 暴搜+dp剪枝优先队列+状压

来源:互联网 发布:如何利用网络招聘 编辑:程序博客网 时间:2024/04/25 06:56

Description


In a shop each kind of product has a price. For example, the price of a flower is 2 ICU (Informatics Currency Units) and the price of a vase is 5 ICU. In order to attract more customers, the shop introduces some special offers. 
A special offer consists of one or more product items for a reduced price. Examples: three flowers for 5 ICU instead of 6, or two vases together with one flower for 10 ICU instead of 12. 
Write a program that calculates the price a customer has to pay for certain items, making optimal use of the special offers. That is, the price should be as low as possible. You are not allowed to add items, even if that would lower the price. 
For the prices and offers given above, the (lowest) price for three flowers and two vases is 14 ICU: two vases and one flower for the reduced price of 10 ICU and two flowers for the regular price of 4 ICU. 

Input

Your program is to read from standard input. The first line contains the number b of different kinds of products in the basket (0 <= b <= 5). Each of the next b lines contains three values c, k, and p. The value c is the (unique) product code (1 <= c <= 999). The value k indicates how many items of this product are in the basket (1 <= k <= 5). The value p is the regular price per item (1 <= p <= 999). Notice that all together at most 5*5=25 items can be in the basket. The b+2nd line contains the number s of special offers (0 <= s <= 99). Each of the next s lines describes one offer by giving its structure and its reduced price. The first number n on such a line is the number of different kinds of products that are part of the offer (1 <= n <= 5). The next n pairs of numbers (c,k) indicate that k items (1 <= k <= 5) with product code c (1 <= c <= 999) are involved in the offer. The last number p on the line stands for the reduced price (1 <= p <= 9999). The reduced price of an offer is less than the sum of the regular prices.

Output

Your program is to write to standard output. Output one line with the lowest possible price to be paid.

Sample Input

27 3 28 2 521 7 3 52 7 1 8 2 10

Sample Output

14

哈哈哈哈哈哈哈哈,这题好玩啊。我写了N个小时,毕竟我是蒟蒻。

这是经典状压dp,但是我不会dp,什么都不会QAQ!!!

个人感觉啊,是图的话,基本都有一个遍历的过程,既然遍历了,那就是搜索了。能建图,一半都可以把答案搜出来,如果搜不出来,那一定是你打开的方式不对 =.=

废话扯完,讲题。

建图部分:

据说是离散化处理坐标,我不会。那就开map映射一下标号,就好了。这是一个单源有向隐式图,终点不确定。终点就是满足要求的点,多终点。单源最短路,鉴定完毕。

状压部分:

题目数据是5*5,所以一件商品数量上限是5,5==(101)b,所以记录商品的状态需要3*5=15个bit位。然后p<999; 25*p << 16 没有爆int,加上(1>>15)-1也没有爆,所以

可以直接用一个int 来存一个状态,状态包括物品的数量和当前的消耗。这时候再看这个题目,不久一个最短路么QAQ。然后你喜欢怎么写就怎么写咯。

PS:状态压缩后要保证能够准确地还原回去,不然那个压缩就没什么意义了

最短路部分:

图论很渣,但是dp我更渣。优先队列的自定义优先级,这是基本功啦。搜索终点是当前的各个商品的数量皆不小于目标数量,因为状态数是(1>>15)-1,这个大小的数组可以

妥妥的开,然后可以用这个数组来约束一下这个搜索,或者说就是一个剪枝吧,好吧,其实这就是dp(=.=)

注意一下,保证每个状态正确的更新,因为考虑到其实每个商品的数量是有可能可以大于7的,所以要实行数位拆分取模

还有就是注意自己写代码的姿势,习惯不一样,别越界,一定不要越界,千万别越界!越界就RE了,你丢掉了一些状态还是有可能A的,毕竟数据一般都有水。RE了就呵呵了

#include <iostream>#include <cstring>#include <map>#include <queue>using namespace std;int dp[1<<16];map<int, int> Map;int b, cnt, End, Edge[110];struct cmp {    bool operator () (int a,int  b)    {return (a>>16) > (b>>16);    }};void getdata(){int c, k, p, n, s;memset(Edge,0,sizeof Edge);cnt = 0;cin>> b;for (int item = 0;item < b; item++){cin>> c>> k>> p;Map[c] = item;End += k<< 3* item;Edge[ cnt ] += 1<< 3* item;Edge[cnt++] += p<< 16;}cin>> s;for (int edge = 0; edge < s; edge++){cin>> n;for( int j = 0; j < n; j++){cin>> c>> k;if(Map.count(c))Edge[cnt] += k<< 3* Map[c];}cin>> p;Edge[cnt] += p<<16;cnt++;}}int bfs(){memset(dp,0x3f,sizeof dp);priority_queue<int, vector<int> , cmp > Q;Q.push(0);while(!Q.empty()){int now = Q.top(); Q.pop();bool ok = true;for(int i = 0; i < b; i++){if( (now&(7<<3*i)) < (End&(7<<3*i)) ){ok = false;break;}}if(ok) return (now>>16);int next = 0;short next_pos;for (int i = 0; i < cnt; i++){next = now +Edge[i];next_pos = short(next);next -= next_pos;if(next_pos>=0 && dp[next_pos] > next){dp[next_pos] = next;for (int t= 0; t< b; t++){int tp = ((now&(7<<3*t)) +(Edge[i]&(7<<3*t)))%(7<<3*t);next += tp;}Q.push(next);}}}return 0;}int main(){ios_base::sync_with_stdio(false);getdata();cout<<bfs()<<endl;}


0 0
原创粉丝点击