usaco shopping offers 解析 and C 语言实现

题意:现在商场正在打折,打折的方式是同时买规定的的物品会比分开买便宜,现在告诉你打折的方式和要买的物品,求最少的钱,有个条件是不可以多买物品。



本题是典型的动态规划,对于动态规划问题,关键是找出其最优子结构,然后写出其递归式,然后,填表及可,另外注意各种边界条件。


对于本题,递归式可写为:

 d[a1][a2][a3][a4][a5]=min(d[a1][a2][a3][a4][a5],d[a1-b1][ a2-b2][ a3-b3][ a4-b4][ a5-b5] + reduce[i] )


d[a1][a2][a3][a4][a5] 表示第 1 个物品买 a1 个,第 2 个物品买 a2 个,第 3 个物品买 a3 个,第 4 个物品买 a4 个,第 5 个物品买 a5 个的最小值。;b1、b2、b3、b4、b5 表示打折要买的物品数目。


/*
ID: abc18711
LANG: C
TASK: shopping
*/

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


struct good
{
	int c;
	int k;
	int r;
};


struct good a[6];

int offer[100][1000];
int reduce[100];

int d[6][6][6][6][6];
int num[100];


int min(int a,int b)
{
	if(a < b)
		return a;
	else
		return b;
}

int main()
{    
	FILE *fin = fopen("shopping.in", "r");
	FILE *fout = fopen("shopping.out", "w");
        
	int s,n,i,j,a1,a2,a3,a4,a5,b1,b2,b3,b4,b5;

        fscanf(fin, "%d", &s);
    
        memset(offer, 0, sizeof(offer));

        for(i=0;i<6;i++) 
		a[i].c=a[i].k=0;

        for(i=1; i<=s; i++)
        {
            fscanf(fin, "%d", &num[i]);
            for(j=1; j<=num[i]; j++)
            {
                fscanf(fin, "%d%d", &a1, &a2);
                offer[i][a1]=a2;
            }
            fscanf(fin, "%d", &reduce[i]);
        }

        fscanf(fin, "%d", &n);

        for(i=1; i<=n; i++)
        {
            fscanf(fin, "%d%d%d", &a[i].c, &a[i].k, &a[i].r);
        }

        d[0][0][0][0][0]=0;

        for(a1=0;a1<=a[1].k;a1++)
        for(a2=0;a2<=a[2].k;a2++)
        for(a3=0;a3<=a[3].k;a3++)
        for(a4=0;a4<=a[4].k;a4++)
        for(a5=0;a5<=a[5].k;a5++)
        {
            d[a1][a2][a3][a4][a5]=a1*a[1].r+a2*a[2].r+a3*a[3].r+a4*a[4].r+a5*a[5].r;
            for(i=1;i<=s;i++)
            {
                if(num[i]>n) continue;
                b1=a1-offer[i][a[1].c];
                b2=a2-offer[i][a[2].c];
		b3=a3-offer[i][a[3].c];
                b4=a4-offer[i][a[4].c];
		b5=a5-offer[i][a[5].c];
                if(b1<0||b2<0||b3<0||b4<0||b5<0) 
			continue;
                d[a1][a2][a3][a4][a5]=min(d[a1][a2][a3][a4][a5],d[b1][b2][b3][b4][b5]+reduce[i]);
            }
        }

        fprintf(fout, "%d\n", d[a[1].k][a[2].k][a[3].k][a[4].k][a[5].k]);
    

	fclose(fin);
	fclose(fout);

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值