POJ 1170 解题报告

3 篇文章 0 订阅
2 篇文章 0 订阅
博客介绍了POJ 1170问题的解题思路,该问题是关于如何以最低成本购买多种商品,包括单独购买和购买促销套装。博主首先尝试了搜索方法,但由于规模和促销套装数量导致超时。接着,博主转向使用动态规划(DP)来解决,定义了一个5维DP数组,表示每种商品的购买数量和所需花费。通过遍历所有可能的购买组合,找到达到目标购买数量的最小成本。博客最后提到了代码优化的重要性。
摘要由CSDN通过智能技术生成

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

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

Sample Output

14

 

 

题目意思就是说,一共有a种商品,每种有b个,a和b都不大于5,每个商品都可以单独卖,也有促销套装卖。

问怎么花最少的钱,把所有商品都买到。

 

一开始认为规模比较小,果断考虑搜索。不过由于促销套装的数量可能很多,用bfs队列膨胀的很快。用dfs也是,肯定TLE。

于是仔细考虑了一下,应该用动态规划dp;

定义dp

 int dp[6][6][6][6][6];

dp[a][b][c][d][e]就表示五种商品分别买a b c d e各所需要花的最少的钱。

如果把每种商品单独买和每种套餐都考虑成一种销售策略,也就是

price[a][b][c][d][e]对应输入中的一行,abcde是五种商品分别的数量,从0到5,price就是这种买法的价格

那么对dp[j1][j2][j3][j4][j5], 有

dp[j1][j2][j3][j4][j5] = min(dp[i1][i2][i3][i4][i5] + price[j1-i1][j2-i2][j3-i3][j4-i4][j5-i5]], dp[i1][i2][i3][i4][i5] + dp[j1-i1][j2-i2][j3-i3][j4-i4][j5-i5]); 

其中i1取值范围是0~j1,以此类推

也就是对于目标购买五种商品 j1 j2 j3 j4 j5个,需要遍历所有上述的i1 i2 i3 i4 i5,看是否有已经发现的dp[i1][i2][i3][i4][i5] 与 dp[j1-i1][j2-i2][j3-i3][j4-i4][j5-i5] 或 price[j1-i1][j2-i2][j3-i3][j4-i4][j5-i5]] 可以组合成dp[j1][j2][j3][j4][j5]的最小值。

说的比较繁琐,不知道怎么说能明了,不过道理不复杂,想一下就能明白。

 

代码:

//#include "stdafx.h"

#include <iostream>
#include <math.h>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <map>
#include <vector>
#include <string.h>
#include <queue>
#include <list>
#include <set>
#include <hash_set>
#include <algorithm>

using namespace std;
using namespace stdext;

#define  FOR(x,y) for(int x = 0;x<y;x++)
#define  FOR1(x,y) for(int x = 1;x<=y;x++)
#define MSET(p) memset(p,0,sizeof(p))
#define inf 0xffffff

int mapping[1000];
int target[5];
int nk;
int dp[6][6][6][6][6];
int sales[6][6][6][6][6];

void caldp(int j1,int j2, int j3, int j4, int j5)
{
	for (int i1 = 0; i1<= j1; i1++)
	{
		for (int i2 = 0; i2 <= j2; i2++)
		{
			for (int i3 = 0; i3 <= j3; i3++)
			{
				for (int i4 = 0; i4 <= j4; i4++)
				{
					for (int i5 = 0; i5 <= j5; i5++)
					{
						if (dp[i1][i2][i3][i4][i5] >= inf)
						{
							continue;
						}
						dp[j1][j2][j3][j4][j5] = min(dp[j1][j2][j3][j4][j5], dp[i1][i2][i3][i4][i5] + dp[j1-i1][j2-i2][j3-i3][j4-i4][j5-i5]);
						dp[j1][j2][j3][j4][j5] = min(dp[j1][j2][j3][j4][j5], dp[i1][i2][i3][i4][i5] + sales[j1-i1][j2-i2][j3-i3][j4-i4][j5-i5]);
					}
				}
			}
		}
	}
	return;
}
int main()
{
	//freopen("in.txt","r",stdin);
	int len;
	cin>>len;
	nk = len;
	int fi[5];
	FOR(i1,6)
	FOR(i2,6)
	FOR(i3,6)
	FOR(i4,6)
	FOR(i5,6)
	{
		dp[i1][i2][i3][i4][i5] = inf;
		sales[i1][i2][i3][i4][i5] = inf;
	}
	dp[0][0][0][0][0] = 0;
	sales[0][0][0][0][0] = 0;
	MSET(target);
	FOR(i,len)
	{
		int c,k,p;
		MSET(fi);
		fi[i] = 1;
		cin>>c>>k>>p;
		mapping[c] = i;

		sales[fi[0]][fi[1]][fi[2]][fi[3]][fi[4]] = min(p,sales[fi[0]][fi[1]][fi[2]][fi[3]][fi[4]] );
		target[i] += k;
	}
	cin>>len;
	FOR(i,len)
	{
		int k;
		cin>>k;
		MSET(fi);
		FOR(j,k)
		{
			int t1,t2;
			cin>>t1>>t2;
			t1 = mapping[t1];
			fi[t1] += t2;
		}
		cin>>k;
		sales[fi[0]][fi[1]][fi[2]][fi[3]][fi[4]] = min(k,sales[fi[0]][fi[1]][fi[2]][fi[3]][fi[4]] );
		
	}

	for (int i1 = 0; i1 <= target[0]; i1++)
	{
		for (int i2 = 0; i2 <= target[1]; i2++)
		{
			for (int i3 = 0; i3 <= target[2]; i3++)
			{
				for (int i4 = 0; i4 <= target[3]; i4++)
				{
					for (int i5 = 0; i5 <= target[4]; i5++)
					{
							caldp(i1,i2,i3,i4,i5);
					}
				}
			}
		}
	}
	int ret = dp[target[0]][target[1]][target[2]][target[3]][target[4]];

	printf("%d\n",ret);
	return 0;
}


 

 

刚刚就没有优化,优化一下能更快一些

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值