USACO 3.3 Shopping Offers
背包问题,dp解决。
dp[i][j][k][m][n]表示第0-4种物品分别购买i-n个时,所需的最小费用。
那么对于每一个offer
dp[i][j][k][m][n] = min ( dp[i][j][k][m][n], dp[i-o[0]][j-o[1]][k-o[2]][m-o[3]][n-o[4]]+offer.cost);
analysis中提出用最短路径的方法来解,思路很巧妙。把”装有不同种数和数量的物品“的篮子看作结点,把offer作为边(把购买一件物品的原始价格看成一种退化的offer),把价格作为边长度。这样就转换成从篮子(0,0,0,0,0)到所求结点的最短路径问题。
代码如下:
上面代码有个严重的bug,谢谢网友“我也凑热闹"指出。由于map所有值都为0。所以未在商品列表中出现的商品的map值都为0,即都映射为第一个商品。现改成将map初始化为-1,并增加判断语句。此外将初始化dp的语句合并到后面,以简化代码。
dp[i][j][k][m][n]表示第0-4种物品分别购买i-n个时,所需的最小费用。
那么对于每一个offer
dp[i][j][k][m][n] = min ( dp[i][j][k][m][n], dp[i-o[0]][j-o[1]][k-o[2]][m-o[3]][n-o[4]]+offer.cost);
analysis中提出用最短路径的方法来解,思路很巧妙。把”装有不同种数和数量的物品“的篮子看作结点,把offer作为边(把购买一件物品的原始价格看成一种退化的offer),把价格作为边长度。这样就转换成从篮子(0,0,0,0,0)到所求结点的最短路径问题。
代码如下:
#include
<
iostream
>
#include < fstream >
using namespace std;
ifstream fin( " shopping.in " );
ofstream fout( " shopping.out " );
#ifdef _DEBUG
#define out cout
#define in cin
#else
#define out fout
#define in fin
#endif
int dp[ 6 ][ 6 ][ 6 ][ 6 ][ 6 ];
struct offer{
int pro_num;
int price;
int product[ 5 ];
int amount[ 5 ];
};
int offer_num;
offer offers[ 100 ];
int map[ 1000 ]; //product id到”按物品出现顺序所给的编号“的映射
int price[ 1000 ];//product id对应的物品价格
int product_num;//物品总数目
int products[ 5 ];//存放product id
int amount[ 5 ];//product 所需的数量
void solve()
{
in >> offer_num;
for ( int i = 0 ;i < offer_num; ++ i){
in >> offers[i].pro_num;
for ( int j = 0 ;j < offers[i].pro_num; ++ j){
in >> offers[i].product[j] >> offers[i].amount[j];
}
in >> offers[i].price;
}
int pro_idx = 0 ;
in >> product_num;
for ( int i = 0 ;i < product_num; ++ i){
in >> products[i];
in >> amount[i];
in >> price[i];
map[ products[i] ] = i;
}
//没有折扣时的价格
for ( int i = 0 ;i <= 5 ; ++ i)
for ( int j = 0 ;j <= 5 ; ++ j)
for ( int k = 0 ;k <= 5 ; ++ k)
for ( int m = 0 ;m <= 5 ; ++ m)
for ( int n = 0 ;n <= 5 ; ++ n){
dp[i][j][k][m][n] =
price[ 0 ] * i +
price[ 1 ] * j +
price[ 2 ] * k +
price[ 3 ] * m +
price[ 4 ] * n;
}
for ( int i = 0 ;i <= 5 ; ++ i)
for ( int j = 0 ;j <= 5 ; ++ j)
for ( int k = 0 ;k <= 5 ; ++ k)
for ( int m = 0 ;m <= 5 ; ++ m)
for ( int n = 0 ;n <= 5 ; ++ n){
int tmp[ 5 ];
for ( int s = 0 ;s < offer_num; ++ s){
memset(tmp, 0 , sizeof (tmp));
for ( int t = 0 ;t < offers[s].pro_num; ++ t){
tmp[map[offers[s].product[t]]] = offers[s].amount[t];
}
if (i >= tmp[ 0 ] && j >= tmp[ 1 ] && k >= tmp[ 2 ] && m >= tmp[ 3 ] && n >= tmp[ 4 ]){
dp[i][j][k][m][n] = min( dp[i][j][k][m][n],
dp[i - tmp[ 0 ]][j - tmp[ 1 ]][k - tmp[ 2 ]][m - tmp[ 3 ]][n - tmp[ 4 ]] +
offers[s].price);
}
}
}
out << dp[amount[ 0 ]][amount[ 1 ]][amount[ 2 ]][amount[ 3 ]][amount[ 4 ]] << endl;
}
int main( int argc, char * argv[])
{
solve();
return 0 ;
}
#include < fstream >
using namespace std;
ifstream fin( " shopping.in " );
ofstream fout( " shopping.out " );
#ifdef _DEBUG
#define out cout
#define in cin
#else
#define out fout
#define in fin
#endif
int dp[ 6 ][ 6 ][ 6 ][ 6 ][ 6 ];
struct offer{
int pro_num;
int price;
int product[ 5 ];
int amount[ 5 ];
};
int offer_num;
offer offers[ 100 ];
int map[ 1000 ]; //product id到”按物品出现顺序所给的编号“的映射
int price[ 1000 ];//product id对应的物品价格
int product_num;//物品总数目
int products[ 5 ];//存放product id
int amount[ 5 ];//product 所需的数量
void solve()
{
in >> offer_num;
for ( int i = 0 ;i < offer_num; ++ i){
in >> offers[i].pro_num;
for ( int j = 0 ;j < offers[i].pro_num; ++ j){
in >> offers[i].product[j] >> offers[i].amount[j];
}
in >> offers[i].price;
}
int pro_idx = 0 ;
in >> product_num;
for ( int i = 0 ;i < product_num; ++ i){
in >> products[i];
in >> amount[i];
in >> price[i];
map[ products[i] ] = i;
}
//没有折扣时的价格
for ( int i = 0 ;i <= 5 ; ++ i)
for ( int j = 0 ;j <= 5 ; ++ j)
for ( int k = 0 ;k <= 5 ; ++ k)
for ( int m = 0 ;m <= 5 ; ++ m)
for ( int n = 0 ;n <= 5 ; ++ n){
dp[i][j][k][m][n] =
price[ 0 ] * i +
price[ 1 ] * j +
price[ 2 ] * k +
price[ 3 ] * m +
price[ 4 ] * n;
}
for ( int i = 0 ;i <= 5 ; ++ i)
for ( int j = 0 ;j <= 5 ; ++ j)
for ( int k = 0 ;k <= 5 ; ++ k)
for ( int m = 0 ;m <= 5 ; ++ m)
for ( int n = 0 ;n <= 5 ; ++ n){
int tmp[ 5 ];
for ( int s = 0 ;s < offer_num; ++ s){
memset(tmp, 0 , sizeof (tmp));
for ( int t = 0 ;t < offers[s].pro_num; ++ t){
tmp[map[offers[s].product[t]]] = offers[s].amount[t];
}
if (i >= tmp[ 0 ] && j >= tmp[ 1 ] && k >= tmp[ 2 ] && m >= tmp[ 3 ] && n >= tmp[ 4 ]){
dp[i][j][k][m][n] = min( dp[i][j][k][m][n],
dp[i - tmp[ 0 ]][j - tmp[ 1 ]][k - tmp[ 2 ]][m - tmp[ 3 ]][n - tmp[ 4 ]] +
offers[s].price);
}
}
}
out << dp[amount[ 0 ]][amount[ 1 ]][amount[ 2 ]][amount[ 3 ]][amount[ 4 ]] << endl;
}
int main( int argc, char * argv[])
{
solve();
return 0 ;
}
上面代码有个严重的bug,谢谢网友“我也凑热闹"指出。由于map所有值都为0。所以未在商品列表中出现的商品的map值都为0,即都映射为第一个商品。现改成将map初始化为-1,并增加判断语句。此外将初始化dp的语句合并到后面,以简化代码。
#include
<
iostream
>
#include < fstream >
using namespace std;
ifstream fin( " shopping.in " );
ofstream fout( " shopping.out " );
#ifdef _DEBUG
#define out cout
#define in cin
#else
#define out fout
#define in fin
#endif
int dp[ 6 ][ 6 ][ 6 ][ 6 ][ 6 ];
struct offer{
int pro_num;
int price;
int product[ 5 ];
int amount[ 5 ];
};
int offer_num;
offer offers[ 100 ];
int map[ 1000 ];
int price[ 1000 ];
int product_num;
int products[ 5 ];
int amount[ 5 ];
void solve()
{
in >> offer_num;
for ( int i = 0 ;i < offer_num; ++ i){
in >> offers[i].pro_num;
for ( int j = 0 ;j < offers[i].pro_num; ++ j){
in >> offers[i].product[j] >> offers[i].amount[j];
}
in >> offers[i].price;
}
int pro_idx = 0 ;
in >> product_num;
// 2009.07.27修改
memset(map, - 1 , sizeof (map));
for ( int i = 0 ;i < product_num; ++ i){
in >> products[i];
in >> amount[i];
in >> price[i];
map[ products[i] ] = i;
}
for ( int i = 0 ;i <= 5 ; ++ i)
for ( int j = 0 ;j <= 5 ; ++ j)
for ( int k = 0 ;k <= 5 ; ++ k)
for ( int m = 0 ;m <= 5 ; ++ m)
for ( int n = 0 ;n <= 5 ; ++ n){
dp[i][j][k][m][n] =
price[ 0 ] * i +
price[ 1 ] * j +
price[ 2 ] * k +
price[ 3 ] * m +
price[ 4 ] * n;
int tmp[ 5 ];
for ( int s = 0 ;s < offer_num; ++ s){
memset(tmp, 0 , sizeof (tmp));
for ( int t = 0 ;t < offers[s].pro_num; ++ t){
// 2009.07.27修改
if ( map[offers[s].product[t]] !=- 1 )
tmp[map[offers[s].product[t]]] = offers[s].amount[t];
}
if (i >= tmp[ 0 ] && j >= tmp[ 1 ] && k >= tmp[ 2 ] && m >= tmp[ 3 ] && n >= tmp[ 4 ]){
dp[i][j][k][m][n] = min( dp[i][j][k][m][n],
dp[i - tmp[ 0 ]][j - tmp[ 1 ]][k - tmp[ 2 ]][m - tmp[ 3 ]][n - tmp[ 4 ]] +
offers[s].price);
}
}
}
out << dp[amount[ 0 ]][amount[ 1 ]][amount[ 2 ]][amount[ 3 ]][amount[ 4 ]] << endl;
}
int main( int argc, char * argv[])
{
solve();
return 0 ;
}
#include < fstream >
using namespace std;
ifstream fin( " shopping.in " );
ofstream fout( " shopping.out " );
#ifdef _DEBUG
#define out cout
#define in cin
#else
#define out fout
#define in fin
#endif
int dp[ 6 ][ 6 ][ 6 ][ 6 ][ 6 ];
struct offer{
int pro_num;
int price;
int product[ 5 ];
int amount[ 5 ];
};
int offer_num;
offer offers[ 100 ];
int map[ 1000 ];
int price[ 1000 ];
int product_num;
int products[ 5 ];
int amount[ 5 ];
void solve()
{
in >> offer_num;
for ( int i = 0 ;i < offer_num; ++ i){
in >> offers[i].pro_num;
for ( int j = 0 ;j < offers[i].pro_num; ++ j){
in >> offers[i].product[j] >> offers[i].amount[j];
}
in >> offers[i].price;
}
int pro_idx = 0 ;
in >> product_num;
// 2009.07.27修改
memset(map, - 1 , sizeof (map));
for ( int i = 0 ;i < product_num; ++ i){
in >> products[i];
in >> amount[i];
in >> price[i];
map[ products[i] ] = i;
}
for ( int i = 0 ;i <= 5 ; ++ i)
for ( int j = 0 ;j <= 5 ; ++ j)
for ( int k = 0 ;k <= 5 ; ++ k)
for ( int m = 0 ;m <= 5 ; ++ m)
for ( int n = 0 ;n <= 5 ; ++ n){
dp[i][j][k][m][n] =
price[ 0 ] * i +
price[ 1 ] * j +
price[ 2 ] * k +
price[ 3 ] * m +
price[ 4 ] * n;
int tmp[ 5 ];
for ( int s = 0 ;s < offer_num; ++ s){
memset(tmp, 0 , sizeof (tmp));
for ( int t = 0 ;t < offers[s].pro_num; ++ t){
// 2009.07.27修改
if ( map[offers[s].product[t]] !=- 1 )
tmp[map[offers[s].product[t]]] = offers[s].amount[t];
}
if (i >= tmp[ 0 ] && j >= tmp[ 1 ] && k >= tmp[ 2 ] && m >= tmp[ 3 ] && n >= tmp[ 4 ]){
dp[i][j][k][m][n] = min( dp[i][j][k][m][n],
dp[i - tmp[ 0 ]][j - tmp[ 1 ]][k - tmp[ 2 ]][m - tmp[ 3 ]][n - tmp[ 4 ]] +
offers[s].price);
}
}
}
out << dp[amount[ 0 ]][amount[ 1 ]][amount[ 2 ]][amount[ 3 ]][amount[ 4 ]] << endl;
}
int main( int argc, char * argv[])
{
solve();
return 0 ;
}