首页 > 试题广场 >

购物单

[编程题]购物单
  • 热度指数:452546 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅
如果要买归类为附件的物品,必须先买该附件所属的主件,且每件物品只能购买一次。
每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。
王强查到了每件物品的价格(都是 10 元的整数倍),而他只有 N 元的预算。除此之外,他给每件物品规定了一个重要度,用整数 1 ~ 5 表示。他希望在花费不超过 N 元的前提下,使自己的满意度达到最大。
满意度是指所购买的每件物品的价格与重要度的乘积的总和,假设设第i件物品的价格为,重要度为,共选中了k件物品,编号依次为j_1,j_2,...,j_k,则满意度为:。(其中 * 为乘号)
请你帮助王强计算可获得的最大的满意度。




输入描述:
输入的第 1 行,为两个正整数N,m,用一个空格隔开。其中 N 表示总钱数, m 为可购买的物品的个数。
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v、p、q。
其中 v 表示该物品的价格,p 表示该物品的重要度,q 表示该物品是主件还是附件。
如果 q=0,表示该物品为主件,如果q>0,表示该物品为附件, q 是所属主件的编号。

数据范围:N<32000,m<60,v<10000,1<=p<=5。


输出描述:
 输出一个正整数,为张强可以获得的最大的满意度。
示例1

输入

1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0

输出

2200
示例2

输入

50 5
20 3 5
20 3 5
10 3 0
10 2 0
10 1 0

输出

130

说明

由第1行可知总钱数N为50以及希望购买的物品个数m为5;
第2和第3行的q为5,说明它们都是编号为5的物品的附件;
第4~6行的q都为0,说明它们都是主件,它们的编号依次为3~5;
所以物品的价格与重要度乘积的总和的最大值为10*1+20*3+20*3=130       
使用纯搜索的方法,求解空间是n个物品中选择购买m个物品(m<n)的排列组合,但是因为这样求解空间过大,一一列举时间不够,所以我采用了蒙特卡洛算法,每次循环列举n个例子,直到达到停止条件,不过很难在1s内收敛到最优解。
#include 
#include 
#include  // 包含时间库用于种子初始化
struct object
{
    int price;
    int importance;
    int kind;
};
int main() {
    int money, num;
    int satisfaction_max;
    scanf("%d %d",&money, &num);
    struct object *items= (struct object *)malloc(num*3*sizeof(int));
    //储存数据
    for(int i=0;i<num;i++)
    {
        scanf("%d %d %d",&items[i].price,&items[i].importance,&items[i].kind);
    }
    //初始化随机数种子
    srand(time(NULL));
    //创建求解空间,求解空间为n*n,为1则买这个物品,为0则不
    char ** solveplace=(char **) malloc(num*sizeof(char*));// 动态分配一个 n x n 的二维数组
    int satisfaction_max_stableCount = 0;//蒙特卡洛算法停止条件
    int satisfaction_max_before=0;
    for(int i=0;i<num;i++)
    {
        solveplace[i]=(char*)malloc(num*sizeof(char)); 
    }   
    SOLVE:
    //使用随机数创建求解例子 
    for(int i=0;i<num;i++)
    {
        for(int j=0;j<num;j++)
        {
            double rand_num = (double)rand() / RAND_MAX; // 生成一个 0 到 1 之间的随机数            
            if(rand_num<0.5)
                solveplace[i][j]=0;
            else
                solveplace[i][j]=1;
        }
    }
    //将不符合附件规定的删除
    for(int i=0;i<num;i++)
    {
        for(int j=0;j<num;j++)
        {
            if(solveplace[i][j]&&items[j].kind)//如果它是附件
            {
                if(solveplace[i][items[j].kind-1]==0)//如果这个附件的主件没有选择
                    solveplace[i][0]=-1;//剔除这个求解,用-1作为标志
            }
        }
    }
    //计算所用的钱,将大于所用钱的的删除
    for(int i=0;i<num;i++)
    {
        if(solveplace[i][0]==-1)
            continue;
        int money_=0;
        for(int j=0;j<num;j++)
        {
            if(solveplace[i][j])
                money_+=items[j].price;
        }
        if(money_>money)//价格超了,删除这个求解
            solveplace[i][0]=-1;
    }
    //寻找剩余可行解中重要值最大的
    for(int i=0;i<num;i++)
    {
        if(solveplace[i][0]==-1)
            continue;
        int satisfaction=0;
        for(int j=0;j<num;j++)
        {
            if(solveplace[i][j])
                satisfaction+=items[j].price*items[j].importance;
        }
        if(satisfaction>satisfaction_max)
            satisfaction_max = satisfaction;
    }
    if(satisfaction_max==satisfaction_max_before)
        satisfaction_max_stableCount++;
    satisfaction_max_before = satisfaction_max;
    //蒙特卡洛算法停止判断
    if(satisfaction_max_stableCount<70000)
    {
        goto SOLVE;
    }
    else
        printf("%d",satisfaction_max);
    return 0;
}
发表于 2024-10-07 19:48:32 回复(0)
看了评论才发现附件不会多于两个。。。写了一个支持任意多个附件的版本,大家将就着看吧。由于提升了问题复杂度,最后两个点老是过不了,就用了个取巧的办法:因为价格都是整十整百的,就都除掉了,问题复杂度能降低十倍百倍。时间复杂度是on3.实现方式算是双重背包问题:1.把主件和他的所有附件看成一个组合,对这个组合算背包问题,能够算出这个组合的价格-价值表格。然后对每个组合算背包问题。
#include <stdio.h>
#include <malloc.h>
#include <math.h>
struct goodssub{
    int price;
    int worth;
    struct goodssub * nxt;
};
struct goodsmain{
    int index;
    int price;
    int worth;
    int sub_num;
    int a[32000];
    struct goodssub* mysub;
};
struct goodsmain goods[60];
int howmanyzero(int n){
    int ret = 0;
    while (n % 10 == 0){
        ret ++;
        n/=10;
    }
    return ret;
}
int main() {
    int price, totnum, mainnum=0;
    scanf("%d %d", &price, &totnum);
    int tmp[60][3];
    int tmpnum=0;
    int minzero = 100;
    for (int i=0; i < totnum; i++){
        int v, p, q;
        scanf("%d %d %d", &v, &p, &q);
        if (minzero > howmanyzero(v)) minzero = howmanyzero(v);
        if (q == 0){
            goods[mainnum].index = i + 1;
            goods[mainnum].price = v;
            goods[mainnum].worth = p;
            goods[mainnum].sub_num = 0;
            goods[mainnum].mysub = NULL;
            mainnum ++;
        }else {
            tmp[tmpnum][0] = v;
            tmp[tmpnum][1] = p;
            tmp[tmpnum][2] = q;
            tmpnum ++ ;
        }
    }
    int  myzero = pow(10, minzero);
    for (int i=0; i < mainnum; i++) goods[i].price /= myzero;
    price /= myzero;
    for (int i=0; i < tmpnum; i++) tmp[i][0] /= myzero;
    for (int i=0; i < tmpnum; i++){
        int thisindex = 0;
        int j;
        for(j=0; j < mainnum; j++) if (goods[j].index == tmp[i][2]) break;
        struct goodsmain *gp = &goods[j];
        struct goodssub *gs ;
        if (gp->sub_num == 0){
            gp->mysub = malloc(sizeof(struct goodssub));
            gs =  gp->mysub;
        }else {
            gs =  gp->mysub;
            for (int ii=0; ii < gp->sub_num - 1; ii++) gs = gs->nxt;
            gs -> nxt = malloc(sizeof(struct goodssub));
            gs = gs->nxt;
        }
        gs->price = tmp[i][0];
        gs->worth = tmp[i][1];
        gs->nxt = NULL;
        gp->sub_num ++;
    }
    int * aaa = malloc(sizeof(int) * (price + 1) * (mainnum + 1));
    for (int i=0; i <= price; i++) aaa[i] = 0;
    for (int i=0; i < mainnum; i++){
        if (goods[i].sub_num == 0){
            for (int ii=0; ii <= price; ii++) goods[i].a[ii] = (ii >= goods[i].price)?goods[i].price * goods[i].worth:0;
        }else{
            int *aa = malloc(sizeof(int) * (price + 1) * (goods[i].sub_num + 1));
            for (int ii=goods[i].price; ii <= price; ii++) aa[ii] = goods[i].price * goods[i].worth;
            struct goodssub *gs = goods[i].mysub;
            for (int jj = 1; jj <= goods[i].sub_num; jj++){
                for (int ii=goods[i].price; ii <= price; ii++){
                    int max = aa[(jj-1) * (price + 1) + ii];
                    if (ii - gs->price >= goods[i].price)
                        if (aa[(jj-1) * (price + 1) + ii - gs->price] + gs->price * gs->worth > max) 
                            max = aa[(jj-1) * (price + 1) + ii - gs->price] + gs->price * gs->worth;
                    aa[jj * (price + 1) + ii ] = max;
                }
                gs = gs->nxt;
            }
            for (int ii=0; ii <= price; ii++) goods[i].a[ii] = (ii < goods[i].price)?0:aa[goods[i].sub_num * (price + 1) + ii];
            free(aa);
        }
        for (int j=0; j<=price; j++){
            int max = 0;
            for (int k=0; k <= j; k++)
                if (aaa[(i) * (price + 1) + k] + goods[i].a[j-k] > max) max = aaa[(i) * (price + 1) + k] + goods[i].a[j-k];
            aaa[(i+1)*(price+1)+j] = max;
        }

    }
    printf("%d", aaa[mainnum * (price + 1) + price] * myzero);
    return 0;
}

发表于 2024-09-09 12:35:27 回复(0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define max(a,b) a>=b?a:b
int main()
{
    int N,m,v,p,q,num=0,k=0;
    scanf("%d %d",&N,&m);
    int money[4][m];
    int position[3][m];
    //初始化
    for(int i=0;i<4;i++)
        for(int j=0;j<m;j++)
            money[i][j]=0;
    //赋值
    for(int i=0;i<m;i++)
    {
        scanf("%d %d %d",&v,&p,&q);
        if(q!=0)
        {
            int j = money[3][q-1]+1;
            money[j][q-1]=v;
            position[j][q-1]=p;
            money[3][q-1] +=1;
            continue;  
        }
        money[0][i]=v;
        position[0][i]=p;
        num++;
    }
    int value[4][num];
    int weight[4][num];
    //处理数据
    for(int i=0;i<m;i++)
    {
        if(money[0][i]==0)
            continue;
        //value
        value[0][k]=money[0][i];
        value[1][k]=money[0][i]+money[1][i];
        value[2][k]=money[0][i]+money[2][i];
        value[3][k]=money[0][i]+money[1][i]+money[2][i];
        //weight
        weight[0][k]=money[0][i]*position[0][i];
        weight[1][k]=money[0][i]*position[0][i]+money[1][i]*position[1][i];
        weight[2][k]=money[0][i]*position[0][i]+money[2][i]*position[2][i];
        weight[3][k]=money[0][i]*position[0][i]+money[2][i]*position[2][i]+money[1][i]*position[1][i];
        k++;
    }

    int ** DP = malloc((N/10+1)*sizeof(int *));
    int max_above = 0;
    for(int i=0;i<(N/10+1);i++)
    {
        DP[i] = malloc(num*sizeof(int));
        for(int j =0;j<num;j++)
        {
            int max_w=0;
            //***附件
            for(int k=0;k<4;k++)    
            {
                int max_p= 0;
                //钱够不够,不够就滚
                if((i*10)<value[k][j])
                    continue;
                for(int temp_j=0;temp_j<j;temp_j++)
                    max_p = max(max_p,DP[(i*10-value[k][j])/10][temp_j]);
                max_w = max(max_w,max_p+weight[k][j]);          
            }
            DP[i][j] = max_w;
            max_above = max(max_above,max_w);
        }
    }
    printf("%d",max_above);
    return 0;
}
记录一下自己的思路
  首先输入N块钱和m个物品,不管怎么说都有一个最佳购物选择,记为.那么块钱的最佳选择是否为若不是,则块钱的最佳选择也不为.由此我们可以得到一个递归式。
  不妨设为在只有i块钱时以为结尾的最大满意值。故该题要求的结果是
  从上面的讨论中我们可以得到
发表于 2024-03-25 20:53:26 回复(0)
#include <stdio.h>
#define max(a,b) (a>b?a:b)
//还有最后一组示例不通过???暂未解决 
int main(){
    int N, m;
    int price[62][4] = {{0}};
    int value[62][4] = {{0}};
    int f[3201] = {0};
    scanf("%d %d", &N, &m);
    int p, q, v;
    N = N/10;//数字过大,价格总是10的倍数,先缩小 
    for(int i = 1; i <= m; i++){
        scanf("%d %d %d", &v, &p, &q);
        v = v / 10;
        if(q == 0){//是主件
            price[i][0] = v;
            value[i][0] = v*p;
        }else{//附件
            if(price[q][1] == 0){//第一个附件
                price[q][1] = v ;
                value[q][1] = p*v;  
            }else{//第二个附件
                price[q][2] = v ;
                value[q][2] = p*v ;
                // price[q][3] = v + price[q][1];
                // value[q][3] = p*v + value[q][1];               
            }
        }
    }
    for(int i = 1; i <= m; i++){
        if(price[i][1] != 0){//有附件存在
            price[i][1] += price[i][0];
            price[i][2] += price[i][0];
            price[i][3] = price[i][1] + price[i][2] - price[i][0];
            value[i][1] += value[i][0];
            value[i][2] += value[i][0];
            value[i][3] = value[i][1] + value[i][2] - value[i][0];            
        }
    }
    // for(int i = 1; i <=m ;i++){
    //     for(int j = 0; j <=3 ; j++){
    //         // printf("%d   ",price[i][j]);
    //         printf("%d   ",value[i][j]);
    //     }
    //     printf("\n");
    // }
    for(int i = 1; i <= m; i++){
        for(int j = N; j > 0 ;j--){
            for(int k = 0; k <= 3 && price[i][k] <= j; k++){
                f[j] = max(f[j], f[j-price[i][k]]+value[i][k]);
            }
        }
    }
    printf("%d",f[N]*10);
    return 0;
}
发表于 2024-01-17 22:38:37 回复(3)
官方解析垃圾,代码没注释,讲解念一遍代码,一点都听不懂
发表于 2023-10-31 19:04:58 回复(0)
记录一下自己的答案
#include <stdio.h>
static int level[61][3201];
static int v[60], p[60], q[60];

int lastbig = 0;
int max(int a, int b)
{
    if (a>=b) {
        lastbig = 0;
        return a;
    } else {
        lastbig = 1;
        return b;
    }
}

int main() {
    int N, m;
    scanf("%d %d", &N, &m);
    N /= 10;
    for (int j = 0; j < m; j++) {
        scanf("%d %d %d", &v[j], &p[j], &q[j]);
        v[j] /= 10;
    }

    for (int j = 0; j < m; j++) {
        int cq = q[j];
        if (cq) {
            cq -= 1;
            for (int i = N - v[j]; i >= 0; i--) {
                if (level[j][i]) continue;
                if (level[cq][i]) {
                    level[60][i+v[j]] = max(level[60][i+v[j]], level[60][i] + v[j]*p[j]);
                    if (lastbig) {
                        for (int k = 0; k < m; k++)
                            level[k][i+v[j]] = level[k][i];
                        level[j][i+v[j]] = 1;
                    }
                }
                else if (i <= N-v[j]-v[cq]){
                    level[60][i+v[j]+v[cq]] = max(level[60][i+v[j]+v[cq]], level[60][i] + v[j]*p[j] + v[cq]*p[cq]);
                    if (lastbig) {
                        for (int k = 0; k < m; k++)
                            level[k][i+v[j]+v[cq]] = level[k][i];
                        level[j][i+v[j]+v[cq]] = 1;
                        level[cq][i+v[j]+v[cq]] = 1;
                    }
                }

            }
        } else {
            for (int i = N - v[j]; i >= 0; i--) {
                if (level[j][i]) continue; 
                level[60][i+v[j]] = max(level[60][i+v[j]], level[60][i] + v[j]*p[j]);
                if (lastbig) {
                    for (int k = 0; k < m; k++)
                        level[k][i+v[j]] = level[k][i];
                    level[j][i+v[j]] = 1;
                }
            }
        }
    }
    printf("%d", level[60][N] * 10);
    return 0;
}


发表于 2023-02-26 20:28:17 回复(0)
#include <stdio.h>

typedef struct goods{
    int prices; //物品的价格
    int value; //满意度
}GOODS ;

int max(int a, int b)
{
    return a>b ? a:b;
}

int main() {
    int N,m,a,b,c;
    GOODS goods[60][3] = {0}; //goods[i][0]代表主件、goods[i][1]代表附件1、goods[i][2]代表附件2
    scanf("%d %d", &N, &m);
    for(int i=1; i<=m; i++)
    {
        scanf("%d %d %d", &a, &b, &c);
        a /= 10; b *= a;
        if (c == 0) 
        {
            goods[i][0].prices = a; goods[i][0].value = b;
        } 
        else 
        {
            if (goods[c][1].prices == 0) 
            {
                goods[c][1].prices = a; goods[c][1].value = b;
            } 
            else 
            {
                goods[c][2].prices = a; goods[c][2].value = b;
            }
        }
    }

    N /= 10; //每件物品的价格(都是 10 元的整数倍)
    int dp[60][3200] = {0};
    for(int i=1; i<=m; i++)
    {
        for(int j=1; j<=N; j++)
        {
            int a = goods[i][0].prices, b = goods[i][0].value;
            int c = goods[i][1].prices, d = goods[i][1].value;
            int e = goods[i][2].prices, f = goods[i][2].value;
            dp[i][j] = j >= a ? max(dp[i-1][j-a] + b, dp[i-1][j]) : dp[i-1][j];
            dp[i][j] = j >= (a+c) ? max(dp[i-1][j-a-c] + b + d, dp[i][j]) : dp[i][j];
            dp[i][j] = j >= (a+e) ? max(dp[i-1][j-a-e] + b + f, dp[i][j]) : dp[i][j];
            dp[i][j] = j >= (a+c+e) ? max(dp[i-1][j-a-c-e] + b + d + f, dp[i][j]) : dp[i][j];     
        }
    }

    printf("%d", dp[m][N]*10);
    return 0;
}

//四种情况:1、主件;2、主件+附件1;3、主件+附件2;4、主件+附件1+附件2
//dp[i][j] = max(物品不放入背包,主件,主件+附件1,主件+附件2,主件+附件1+附件2)
/*
int a = prices[i][0], b = value[i][0];
int c = prices[i][1], d = value[i][1];
int e = prices[i][2], f = value[i][2];
dp[i][j] = j >= a ? max(dp[i-1][j-a] + b, dp[i-1][j]) : dp[i-1][j];
dp[i][j] = j >= (a+c) ? max(dp[i-1][j-a-c] + b + d, dp[i][j]) : dp[i][j];
dp[i][j] = j >= (a+e) ? max(dp[i-1][j-a-e] + b + f, dp[i][j]) : dp[i][j];
dp[i][j] = j >= (a+c+e) ? max(dp[i-1][j-a-c-e] + b + d + f, dp[i][j]) : dp[i][j];
*/

发表于 2023-02-06 23:31:49 回复(1)
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
题目没看懂,这个怎么算出来结果是2200的?
发表于 2022-06-23 00:01:14 回复(1)
思想:
    首先 将物品收集起来,然后排序,排序规则(附件必须排在对应的主件后面,附件与主件之间,不得存在其他主件或其它主件的附件;) 排序完成后,存放在thingsArray中,供下面使用;
   然后 构建dp二维数组。 dp[i][j] 表示 截止到第i+1 件商品,在预算为j * 10 时,所能选择出的最大价值;
  那么 dp[i][j] 就存在以下几种情况:
1、 当前thingsArray[i]中的物品是主件,那么拆分为两种情况
    a。 选择thingsArray[i] 这个物品,(当然能否选择这个物品,还需要根据钱是否充足而定) 到这里,跟0-1 背包问题就一模一样了。 如果可以选择,那么最大价值就是 dp[i-1][j * 10 - 当前物品价格] + 当前物品价格*当前物品重要度
    b。 不选择thingsArray[i] 这个物品;由于不选择这个物品,所以无需关心其它物品的情况,直接选择前i-1 个物品就可以; 那么 最大价值数就为  dp[i-1][j]; 
  最后,取a、b 值中的最大值;
2、当前thingsArray[i]中的物品是附件,且thingsArray[i-1]的物品是主件;说明,当前是第一个附件;那么拆分为两种情况
  a。 选择thingsArray[i] 这个物品,由于这个物品是附件,选择该物品,会导致主件也必须要选择,(当然能否选择这个物品,还需要根据钱是否大于 这个物品的价格 +thingsArray[i-1]物品的价格 而定) ,若可以选择,则最大价值为   dp[i-2][j * 10 - thingsArray[i].price - thingsArray[i-1].price] + thingsArray[i]的满意度 + thingsArray[i -1 ]的满意度;
  
  b。 不选择thingsArray[i] 这个物品;由于不选择这个物品,所以无需关心其它物品的情况,直接选择前i-1 个物品就可以; 那么 最大满意度就为  dp[i-1][j]; 
   最后,取a、b 值中的最大值;

3、当前thingsArray[i]中的物品是附件,且thingsArray[i-1]的物品是附件;说明,当前是第二个附件;那么拆分为三种情况
  a。 单独选择thingsArray[i] 这一个附件,由于这个物品是附件,选择该物品,会导致主件也必须要选择,(当然能否选择这个物品,还需要根据钱是否大于 这个物品的价格 +thingsArray[i-2]物品的价格 而定) ,若可以选择,则最大价值为   dp[i-3][j * 10 - thingsArray[i].price - thingsArray[i-2].price] + thingsArray[i]的满意度 + thingsArray[i -2 ]的满意度;
  b。 选择thingsArray[i] 和  thingsArray[i -1 ]两个附件,由于这2个物品是附件,选择该2个物品,会导致主件也必须要选择,(当然能否选择这个物品,还需要根据钱是否大于 这个物品的价格 +thingsArray[i-1]物品的价格 +thingsArray[i-2]物品的价格 而定) ,若可以选择,则最大价值为   dp[i-3][j * 10 - thingsArray[i].price - thingsArray[i-1].price- thingsArray[i-2].price] + thingsArray[i]的满意度 + thingsArray[i -1 ]的满意度+ thingsArray[i -2 ]的满意度;
  c。 不选择thingsArray[i] 这个物品;由于不选择这个物品,所以无需关心其它物品的情况,直接选择前i-1 个物品就可以; 那么 最大满意度就为  dp[i-1][j]; 
   最后,取a、b、c值中的最大值;
  这里再进行迭代时,如果当前是附件且要选择附件的话,不是按照原有背包问题向前迭代一步,而是直接迭代到主件前,所以必须保证排序时,附件必须跟在主件后面;
  
  代码如下:
  
  
#include<stdio.h>


typedef struct Things {
    int index;
    int price;
    int importance;
    int pIndex;
    int fujian[2];
    int fujianIndex;
};

int getZhuId(struct Things one) {
    if (one.pIndex > 0) {
        return one.pIndex;
    }
    return one.index;
}

int comp(struct Things first, struct Things second) {
    if (getZhuId(first) < getZhuId(second)) {
        return -1;
    }

    if (getZhuId(first) > getZhuId(second)) {
        return 1;
    }

    // zhuid equal
    if (first.pIndex == 0) {
        return -1;
    }
    if (second.pIndex == 0) {
        return 1;
    }

    // all is fujian ,then sort with index
    return first.index - second.index;
}

int max(int a, int b) {
    if (a > b) {
        return a;
    }

    return b;
}

int getPricePlusImport(struct Things tg) {
    return tg.price * tg.importance;
}


int main(){
    

int allMoney = 0;
    int count = 0;

    struct Things thingArray[60];

    while (scanf("%d %d", &allMoney, &count) != EOF) {
        for (int i = 1; i < count + 1; i++) {
            struct Things tg;
            tg.index = i;
            tg.fujianIndex = -1;
            scanf("%d %d %d", &tg.price, &tg.importance, &tg.pIndex);

            thingArray[i - 1] = tg;
        }

        // resort zhujian sort with fujian
        for (int i = 0; i < count; i++) {
//            struct Things curr = thingArray[i];
            int minIndex = i;
            for (int j = i + 1; j < count; j++) {
                struct Things curr = thingArray[j];
                struct Things min = thingArray[minIndex];

                if (comp(curr, min) < 0) {
                    minIndex = j;
                }
            }

            // swap minIndex with i point
            struct Things temp = thingArray[i];
            thingArray[i] = thingArray[minIndex];
            thingArray[minIndex] = temp;
        }

        int col = (allMoney / 10)  + 1;
        int dp[count][col];

        for (int i = 0; i < count; i++) {
            for (int j = 0; j < col; j++) {
                if (j == 0) {
                    dp[i][j] = 0;
                    continue;
                }


                // loop judge


                int money = j * 10;
                if (i == 0) {
                    int value = 0;
                    if (money < thingArray[i].price) {
                        dp[i][j] = 0;
                        continue;
//                        return 0;
                    }

                    dp[i][j] = getPricePlusImport(thingArray[i]);
                    continue;
//                    return getPricePlusImport(thingArray[i]);
                }

                //not use i;
                int notUseI = dp[i - 1][j];

                // use i;
                int useI;
                // things on i is zhujian
                if (thingArray[i].pIndex == 0) {
                    // can't use i
                    if (money < thingArray[i].price) {
                        dp[i][j] = notUseI;
                        continue;
//            return 0;
//                        return notUseI;
                    }

                    // can use i
                    useI = dp[i - 1][ (money - thingArray[i].price) / 10] + getPricePlusImport(thingArray[i]);

                    dp[i][j] = max(notUseI, useI);
                    continue;
//                    return max(notUseI, useI);
//        return 0;
                }

                // things on i is fujian
                int fujianIndex = (thingArray[i - 1].pIndex == 0) ? 2 : 3;

                // with first fujian
                if (fujianIndex == 2) {
                    int needMoney = thingArray[i - 1].price + thingArray[i].price;

                    // can't use i
                    if (money < needMoney) {
                        dp[i][j] = notUseI;
                        continue;
//                        return notUseI;
//            return 0;
                    }

                    // can use i, fujian must use with zhujian ,so i must -2
                    if (i < 2) {
                        useI = getPricePlusImport(thingArray[i]) + getPricePlusImport(thingArray[i - 1]);
                    } else {
                        useI = dp[i - 2][ (money - needMoney) / 10] + getPricePlusImport(thingArray[i]) +
                               getPricePlusImport(thingArray[i - 1]);
                    }

                    dp[i][j] = max(notUseI, useI);
                    continue;
//                    return max(notUseI, useI);
//        return 0;
                }

                // with secord fujian
                if (fujianIndex == 3) {
                    int singleUse1 = 0;
                    int doubleUse = 0;

                    // single fujian with zhujian
                    int needMoney = thingArray[i - 2].price + thingArray[i].price;

                    // single fujian with zhujian can't use i, then don't consider double use
                    if (money < needMoney) {
                        dp[i][j] = notUseI;
                        continue;
//                        return notUseI;
//            return 0;
                    }

                    // can use i, fujian must use with zhujian ,so i must -2
                    if (i <= 2) {
                        singleUse1 = getPricePlusImport(thingArray[i]) + getPricePlusImport(thingArray[i - 2]);
                    } else {
                        singleUse1 = dp[i - 3][ (money - needMoney) / 10] + getPricePlusImport(thingArray[i]) +
                                     getPricePlusImport(thingArray[i - 2]);
                    }

                    // double use fujian
                    needMoney = thingArray[i - 2].price + thingArray[i].price + thingArray[i - 1].price;
                    // can't double use, then return
                    if (money < needMoney) {
                        dp[i][j] = max(notUseI, singleUse1);
                        continue;
//                        return max(notUseI, singleUse1);
//            return 0;
                    }

                    if (i <= 2) {
                        doubleUse = getPricePlusImport(thingArray[i]) + getPricePlusImport(thingArray[i - 2]) +
                                    getPricePlusImport(thingArray[i - 1]);
                    } else {
                        doubleUse = dp[i - 3][ (money - needMoney) / 10] + getPricePlusImport(thingArray[i]) +
                                    getPricePlusImport(thingArray[i - 2]) + getPricePlusImport(thingArray[i - 1]);
                    }

                    singleUse1 = max(notUseI, singleUse1);

                    dp[i][j] = max(singleUse1, doubleUse);
                    continue;
//                    return max(singleUse1, doubleUse);
//        return 0;
                }


                // loop judge   end
                printf("invalid code execute, %d, %d", i, j);

            }
        }


        printf("%d", dp[count -1][col - 1]);
    }
}



发表于 2022-05-31 00:36:58 回复(0)
#include <stdio.h>
#define       N        60
#define       M        32000
int price[N][3],value[N][3],f[N][M];    //二维数组的第一列代表主件的属性,第2和3列分别表示附件1和2的属性
int max(int a,int b)                    //其中price二维数组存储价格,value二维数组存储价值(价格*重要度)
{                                       //f二维数组的值,表示在n个主件(包含附件)可购买,且预算为m情况下的最大价值之和
    return (a>b?a:b);
}
int main()
{
    int m,n,i,p1,w,z,j,p[N][3],v[N][3],temp[5];    //二维数组p和v与上述描述的二维数组作用相似,不过此时是从第1行依行逐次存放物品属性
    scanf("%d%d",&m,&n);                  //输入钱m和可购买的物件n
    for(i=1;i<=n;i++)                    
    {
        scanf("%d%d%d",&p1,&w,&z);      //输入每一件物品的价格p,重要度w,是否主件标志z
        if(z==0)                
        {
            price[i][0]=p1;            //若z==0,表示为主件,属性存放在第i行的第0列
            value[i][0]=p1*w;
        }
        else
        {
            if(price[z][1]==0)        //若有第一个出现的附件,其属性存放在第z行的第1列
            {
                price[z][1]=p1;
                value[z][1]=p1*w;
            }
            else
            {
                price[z][2]=p1;        //若有第二个出现的附件,其属性存放在第z行的第2列
                value[z][2]=p1*w;                 
            }
        }
    }
    for(i=1,j=1;i<=n;i++)            //将以上二维数组的值,按顺序转移到新的二维数组中,这样就不会有很多附件的0的数据穿插其中
    {
        if(price[i][0]!=0)
        {
            p[j][0]=price[i][0];p[j][1]=price[i][1];p[j][2]=price[i][2];
            v[j][0]=value[i][0];v[j][1]=value[i][1];v[j][2]=value[i][2];
            j++;
        }
    }
    n=j-1;                      //n表示主件个数
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            for(w=0;w<5;w++)
            {
                temp[w]=0;        //temp数组存放价值
            }
            temp[0]=f[i-1][j];    //temp[0]表示不买第i个主件所能够得到的最大价值之和
            if(j>=p[i][0])
            {
                temp[1]=f[i-1][j-p[i][0]]+v[i][0];    //temp[1]表示买第i个主件(仅主件)后所能够得到的最大价值之和
            }
            if(j>=(p[i][0]+p[i][1]))
            {
                temp[2]=f[i-1][j-p[i][0]-p[i][1]]+v[i][0]+v[i][1];        //temp[2]表示买第i个主件+附件1后所能够得到的最大价值之和
            }
            if(j>=(p[i][0]+p[i][2]))
            {                                                            //下同
                temp[3]=f[i-1][j-p[i][0]-p[i][2]]+v[i][0]+v[i][2];
            }
            if(j>=(p[i][0]+p[i][1]+p[i][2]))
            {
                temp[4]=f[i-1][j-p[i][0]-p[i][1]-p[i][2]]+v[i][0]+v[i][1]+v[i][2];
            }
            f[i][j]=max(temp[4],max(max(temp[0],temp[1]),max(temp[2],temp[3])));        //取数组temp内最大值,存放于f[i][j]
        }
    }
    printf("%d\n",f[n][m]);            //打印f[n][m],即在n个主件(包含附件)可购买,且预算为m情况下的最大价值之和
    return 0;
}

//写了很久,终于写出来了,dp是真难啊

发表于 2022-04-18 16:15:43 回复(1)
布响写辣  写一天只过了1/3

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

int max(int a, int b){
    return a>b?a:b;
}

int main(){
    int N, m, i, j;
    while(scanf("%d %d", &N, &m) != EOF){
        int v[m+1], p[m+1], q[m+1];
        int dp[m+1][N+1];//i个物品,有j钱
        int appendix[m+1][3];
        int count = 0;
        memset(dp, 0, sizeof(dp));
        memset(appendix, 0, sizeof(appendix));//附件数=0
        v[0] = p[0] = 0;
        for(i=1; i<=m; i++){
            scanf("%d %d %d", &v[i], &p[i], &q[i]); //v=价格,p=重要 ,q主附件
        }
        j = 1;
        q[0] = -1;
        for(i=1; i<=m; i++){
            if(q[i]>0){
                appendix[q[i]][j++] = i;//记录主剑的附件号码
            }
        }
        for(i=1; i<=m; i++){
            if(q[i] > 0){
                count++;
            }
            for(j=10; j<=N; j+=10){
                if(q[i] == 0){
                    if(j - v[i] >= 0){
                            dp[i][j] = max(dp[i-1-count][j-v[i]] + v[i]*p[i], dp[i-1-count][j]);
                        if(j-v[i]-v[appendix[i][1]] >= 0 && appendix[i][1] > 0){
                            dp[i][j] = max(dp[i-1-count][j-v[i]-v[appendix[i][1]]] + v[i]*p[i]+ v[appendix[i][1]]*p[appendix[i][1]], dp[i][j]);
                        }
                        if(j-v[i]-v[appendix[i][2]] >= 0 && appendix[i][2] > 0){
                            dp[i][j] = max(dp[i-1-count][j-v[i]-v[appendix[i][2]]] + v[i]*p[i]+ v[appendix[i][2]]*p[appendix[i][2]], dp[i][j]);
                        }
                        if(j-v[i]-v[appendix[i][1]]-v[appendix[i][2]] >= 0 && appendix[i][2] > 0 && appendix[i][1] > 0){
                            dp[i][j] = max(dp[i-1-count][j-v[i]-v[appendix[i][1]]-v[appendix[i][2]]] + v[i]*p[i]+ v[appendix[i][1]]*p[appendix[i][1]] + v[appendix[i][2]]*p[appendix[i][2]], dp[i][j]);
                        }
                    }else{
                        dp[i][j] = dp[i-1-count][j];
                    }
                }
            }
            if(q[i] == 0){
                count = 0;
            }
        }
        printf("%d", dp[m][N]);
    }
    return 0;
}


发表于 2022-03-24 16:50:02 回复(2)
#include <stdio.h>
int max(int a,int b){
    return a>b?a:b;
}
int main(void){
    //背包问题延展,有附件,最多两个,要考虑到附件
    int N,m;
    while (scanf("%d %d",&N,&m)!=EOF) {
        int value[63][3]={0};
        int weight[63][3]={0};
        int q=0,p=0,v=0;
        for(int i=1;i <= m;i++)
        {
            scanf("%d %d %d",&v,&p,&q);
              if(q){//附件
                if(!value[q][1]){//第一个附件
                    value[q][1] = v;//价格
                    weight[q][1] = v*p;//重要度
                }else{//第二个附件
                    value[q][2] = v;
                    weight[q][2] = ***bsp;               }
            }else{//主件
                value[i][0] = v;
                weight[i][0] = ***bsp;           }
        }
        int n=N/10,value_total = 0,weight_total = 0;
        int total_max[3200] = {0};
        for(int i=1;i <= m;i++)
        {
            for(int j=n;j >= value[i][0]/10;j--)
            {
                total_max[j] = max(total_max[j],total_max[j - value[i][0]/10] + weight[i][0]);
            
            value_total = value[i][1]/10 + value[i][0]/10;
            weight_total = weight[i][1] + weight[i][0];
            if(value[i][1] && j >= value_total)
            {
                total_max[j] = max(total_max[j],total_max[j - value_total] + weight_total);
            }
                value_total += value[i][2]/10;
            weight_total += weight[i][2];
            if(value[i][2] && j >= value_total)
            {
                total_max[j] = max(total_max[j],total_max[j - value_total] + weight_total);
            }
        }
        }
        printf("%d\n",total_max[n]);
    }
    return 0;
    }

发表于 2021-08-25 17:44:56 回复(2)