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)到所求结点的最短路径问题。

代码如下:
#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;
}


上面代码有个严重的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;
}




posted on 2009-07-07 19:16 YZY 阅读(416) 评论(2)  编辑 收藏 引用 所属分类: Algorithm动态规划图论

评论

# re: USACO 3.3 Shopping Offers 2009-07-27 11:18 我也凑热闹

我怀疑你有一个地方是错误的。就是你用map映射的地方。注意题目并没说优惠中的商品一定出现在购买的之中。

所以类似
1
1 3 2 5
1
4 2 3
答案应该是6而不是5
对吧?  回复  更多评论   

# re: USACO 3.3 Shopping Offers 2009-07-27 14:09 YZY

是的,确实有问题。因为map的初始化值为0。这样所有未出现在优惠商品中的商品的map值都变成第一个商品了。谢谢你指出错误。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

统计

常用链接

留言簿(2)

随笔分类

随笔档案

搜索

积分与排名

最新评论

阅读排行榜