1. 程式人生 > 其它 >POJ 172 Shopping Offers|動態規劃|狀態壓縮

POJ 172 Shopping Offers|動態規劃|狀態壓縮

技術標籤:POJ演算法c++c#

題目描述

總時間限制:1000ms 記憶體限制:65536kB

描述


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.

輸入

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.

輸出

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

樣例輸入

2
7 3 2
8 2 5
2
1 7 3 5
2 7 1 8 2 10

樣例輸出

14

問題解決

方法一:動態規劃-5維dp

因為物品不超過5種,每個物品的個數不超過5個,能夠想到的最直接的方法就是使用五維dp,每一維代表了每個物品的購買情況

時間原因,先copy一下:https://www.cnblogs.com/liushaobo/p/4373768.html

#include <stdio.h>
#include <string.h>
#include <limits.h>

int code[6];       //商品程式碼
int num[6];        //商品數量
int price[6];      //商品價格
int special_num[100][6]; //促銷專案各個商品數量
int special_cnt[100];    //促銷專案的商品數量
int special_price[100];  //促銷專案價格
int basket;              
int special;
int dp[6][6][6][6][6];

int Decode (int c){
	int i;
	for (i=1; i<=5; ++i){
		if (code[i] == c)
			break;
	}
	return i;
}

void Init(){
	int i;
	int j;
	int c;
	int k;
	int index;

	scanf ("%d", &basket);
	for (i=1; i<=basket; ++i){
		scanf ("%d%d%d", &code[i], &num[i], &price[i]);
	}
	scanf ("%d", &special);
	for (i=1; i<=special; ++i){
		scanf ("%d", &special_cnt[i]);
		for (j=1; j<=special_cnt[i]; ++j){
			scanf ("%d%d", &c, &k);
			index = Decode (c);
			special_num[i][index] = k;
		}
		scanf ("%d", &special_price[i]);
	}
}

void Lowest_Price (){
	int i1, i2, i3, i4, i5;
	int i;
	int tmp1, tmp2;
	memset (dp, -1, sizeof(dp));
	dp[0][0][0][0][0] = 0;
	for (i1=0; i1<=num[1]; ++i1){
		for (i2=0; i2<=num[2]; ++i2){
			for (i3=0; i3<=num[3]; ++i3){
				for (i4=0; i4<=num[4]; ++i4){
					for (i5=0; i5<=num[5]; ++i5){
						tmp1 = INT_MAX;
						tmp2 = INT_MAX;
						for (i=1; i<=special; ++i){
							if (i1 >= special_num[i][1] && 
								i2 >= special_num[i][2] &&
								i3 >= special_num[i][3] &&
								i4 >= special_num[i][4] &&
								i5 >= special_num[i][5]){
								tmp2 = dp[i1-special_num[i][1]]
										 [i2-special_num[i][2]]
										 [i3-special_num[i][3]]
										 [i4-special_num[i][4]]
										 [i5-special_num[i][5]] + special_price[i];
							if (tmp1 > tmp2)
								tmp1 = tmp2;
							}
						}
						if (tmp1 != INT_MAX){
							dp[i1][i2][i3][i4][i5] = tmp1;
						}
						else{
							dp[i1][i2][i3][i4][i5] = i1 * price[1] + i2 * price[2]
									+ i3 * price[3] + i4 * price[4] + i5 * price[5];
						}
					}
				}
			}
		}
	}
	printf ("%d\n", dp[num[1]][num[2]][num[3]][num[4]][num[5]]);
}

int main(void){
	Init ();
	Lowest_Price ();

	return 0;
}

方法二:動態規劃-狀態壓縮

狀態壓縮實現了每一個狀態的簡化表示

#include<iostream>
#include<algorithm>
#include<cstring>
#define INF 0x3f3f3f3f
#define N 1005

using namespace std;

struct node{
	int num,val;
};

node book[N];
int dp[100000];
int map[N];
int six[10];

int main()
{
	int n,id,m,num,val,sum=0,Max=0;
	ios::sync_with_stdio(false);
	six[0]=1;
	for(int i=1;i<=6;i++)
	{
		six[i]=six[i-1]*6;
	}
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>id>>num>>val;
		map[id]=i-1;
		sum+=num*val;
		Max+=num*six[i-1];
		book[i].num=six[i-1];
		book[i].val=val;
	}
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		int k;
		cin>>k;
		book[i+n].num=0;
		while(k--)
		{
			cin>>id>>num;
			book[i+n].num+=six[map[id]]*num;
		}
		cin>>book[i+n].val;
	}
	memset(dp,INF,sizeof(dp));
	dp[0]=0;
	for(int i=1;i<=n+m;i++)
	{
		for(int j=book[i].num;j<=Max;j++)
		{
			dp[j]=min(dp[j],dp[j-book[i].num]+book[i].val);
		}
	}
	printf("%d\n",min(sum,dp[Max]));
	return 0;
 }