c語言解決購物單問題

題目描述

王強今天很開心,公司發給N元的年終獎。王強決定把年終獎用於購物,他把想買的物品分爲兩類:主件與附件,附件是從屬於某個主件的,下表就是一些主件與附件的例子:

主件 附件
電腦 打印機,掃描儀
書櫃 圖書
書桌 檯燈,文具
工作椅 無

如果要買歸類爲附件的物品,必須先買該附件所屬的主件。每個主件可以有 0 個、 1 個或 2 個附件。附件不再有從屬於自己的附件。王強想買的東西很多,爲了不超出預算,他把每件物品規定了一個重要度,分爲 5 等:用整數 1 ~ 5 表示,第 5 等最重要。他還從因特網上查到了每件物品的價格(都是 10 元的整數倍)。他希望在不超過 N 元(可以等於 N 元)的前提下,使每件物品的價格與重要度的乘積的總和最大。
設第 j 件物品的價格爲 v[j] ,重要度爲 w[j] ,共選中了 k 件物品,編號依次爲 j 1 , j 2 ,……, j k ,則所求的總和爲:
v[j 1 ]w[j 1 ]+v[j 2 ]w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 爲乘號)
請你幫助王強設計一個滿足要求的購物單。

2.輸入輸出

輸入描述:
輸入的第 1 行,爲兩個正整數,用一個空格隔開:N m

(其中 N ( <32000 )表示總錢數, m ( <60 )爲希望購買物品的個數。)

從第 2 行到第 m+1 行,第 j 行給出了編號爲 j-1 的物品的基本數據,每行有 3 個非負整數 v p q

(其中 v 表示該物品的價格( v<10000 ), p 表示該物品的重要度( 1 ~ 5 ), q 表示該物品是主件還是附件。如果 q=0 ,表示該物品爲主件,如果 q>0 ,表示該物品爲附件, q 是所屬主件的編號)

輸出描述:
輸出文件只有一個正整數,爲不超過總錢數的物品的價格與重要度乘積的總和的最大值( <200000 )。

3.解題思路

此題目可先化簡爲分組揹包問題,再求解.

4.源碼實現

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

/* 有條件分組揹包問題(購物單問題)
 * p = 5
 * h = (800, 2, 0), (400, 5, 1), (300, 5, 1), 
 *     (400, 3, 0), (500, 2, 0)
 * w = (800,  1200, 1100, 1500), ( 400), ( 500)
 * v = (1600, 3600, 3100, 5100), (1200), (1000)
 * c = 1000
 */

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

int main()
{
    /*int w[61][11] = {{0, 0}, {4,  80,   120,  110,  150}, {1,   40}, {1,   50}};
    int v[61][11] = {{0, 0}, {4, 1600, 3600, 3100, 5100}, {1, 1200}, {1, 1000}};*/
    int w[61][11];
    int v[61][11];
    int u[61][3201];
    int m[61][3201];
    int h[3][61];
    int b[61][51];
    int d[61];
    int g[61];
    int x[61];
    int t[5];
    int r[61][10][4];
    int n = 3;
    int s = 0;
    int c = 100;
    int z = 0;
    int l;
    int i, j, k;

    j = 1;

    memset(m, 0x00, sizeof(m));
    memset(u, 0x00, sizeof(u));
    memset(r, 0x00, sizeof(r));
    memset(w, 0x00, sizeof(w));
    memset(v, 0x00, sizeof(v));

    scanf("%d %d", &c, &s);

    c /= 10;

    for(i=1; i<=s; i++)
    {
        scanf("%d %d %d", &h[0][i], &h[1][i], &h[2][i]);

        if(!h[2][i])
        {
            b[j][0] = i;        /*第j個組的主件的行數*/
            d[i] = j;           /*第i行屬於哪個組*/
            j++;                /*組數量+1*/
        }
        else
        {
            t[0] = h[2][i];     /*附件屬於哪一行的主件*/
            t[1] = d[t[0]];     /*主件屬於哪一個組*/
            g[t[1]]++;          /*組元素加一*/
            t[2] = g[t[1]];     /*組元素編號*/
            b[t[1]][t[2]] = i;  /*組中的附件編號所屬行數*/
        }
    }

    l = j - 1;                  /*組個數*/

    /*(for(i=1; i<=l; i++)
    {
        for(j=0; j<=g[i]; j++)
        {
            printf("b[%d][%d]=%d ", i, j, b[i][j]);
        }

        printf("\n");
    }*/

    for(i=1; i<=l; i++)
    {
        /*無附件情況*/
        t[0] = 1;
        t[1] = b[i][0];                             /*組中的主件所屬行數*/
        w[i][t[0]] = h[0][t[1]] / 10;               /*主件價格*/
        v[i][t[0]] = h[1][t[1]] * h[0][t[1]];       /*主件目標權重*/
        r[i][t[0]][0] = 1;                          /*第i組第幾種排列方式*/

        t[0]++;

        /*一種附件情況*/
        for(j=1; j<=g[i]; j++)
        {
            t[1] = b[i][0];
            t[2] = b[i][j];

            r[i][t[0]][0] = 1;
            r[i][t[0]][j] = t[1];

            w[i][t[0]] = (h[0][t[1]] + h[0][t[2]]) / 10;
            v[i][t[0]] = h[1][t[1]] * h[0][t[1]] + h[1][t[2]] * h[0][t[2]];

            t[0]++;
        }

        /*兩種附件情況*/
        for(j=1; j<=g[i]; j++)
        {
            for(k=j+1; k<=g[i]; k++)
            {
                t[1] = b[i][0];
                t[2] = b[i][j];
                t[3] = b[i][k];

                r[i][t[0]][0] = 1;
                r[i][t[0]][j] = 1;
                r[i][t[0]][k] = 1;

                w[i][t[0]] = (h[0][t[1]] + h[0][t[2]] + h[0][t[3]]) / 10;
                v[i][t[0]] = h[1][t[1]] * h[0][t[1]] + h[1][t[2]] * h[0][t[2]] + h[1][t[3]] * h[0][t[3]];

                t[0]++;
            }
        }

        w[i][0] = t[0] - 1;
        v[i][0] = w[i][0];
    }

    /*for(i=1; i<=l; i++)
    {
        for(k=1; k<=w[i][0]; k++)
        {
            printf("w[%d][%d]=%d\n", i, k, w[i][k]);
        }
    }*/

    n = l;

    for(i=1; i<=n; i++)
    {
        for(j=1; j<=c; j++)
        {
            z = m[i-1][j];

            for(k=1; k<=w[i][0]; k++)
            {
                if(j >= w[i][k])
                {
                    m[i][j] = max(z, m[i-1][j-w[i][k]]+v[i][k]);

                    if(m[i][j] > z)
                    {
                        u[i][j] = k;
                        z = m[i][j];
                    }
                }
                else
                {
                    m[i][j] = z;
                }
            }
        }
    }

    /*for(i=1; i<=n; i++)
    {
        for(j=1; j<=c; j++)
        {
            printf("%d\t", m[i][j]);
        }

        printf("\n");
    }*/

    printf("%d\n", m[n][c]);

    for(i=n; i>=1; i--)
    {
        if(u[i][c])
        {
            x[i] = u[i][c];
            c -= w[i][x[i]];
        }
        else
        {
            x[i] = 0;
        }
    }

    /*for(i=1; i<=n; i++)
    {
        printf("%d\t", x[i]);
    }

    printf("\n");*/

    return 0;
}

5.編譯源碼

$ gcc -o example examle.c -std=c89

6.運行及其結果

$ ./example
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
2200
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章