码迷,mamicode.com
首页 > 其他好文 > 详细

砝码称重3

时间:2019-12-30 19:31:44      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:http   无限   out   visio   没有   ted   tail   mys   重复数   

参考

https://blog.csdn.net/livelylittlefish/article/details/6555347

假设有280g盐,有一架天平,有两个砝码,分别是4g和14g 。能否在3次内将280g食盐分为100g和180g两堆,请详细描述你的解决方法。

这是另外一种砝码称重问题,类似,但是又不同。砝码称重 这个是给定无限数量砝码,只需计算能不能组成一个重量,不用知道如何组合。砝码称重1是给定砝码个数和重量,以及可以组合的重量,求出任意一种重量是如何组合的。砝码称重2 给定重量和拆分的砝码个数,求拆分后每个砝码的重量。这道题是给定重量和砝码,求如何拆分物体。看似相同,实际上每一个都不一样的。

我们知道4和14可以有这几种组合 0 4 10 14 18,那么问题就是280g物品如何在3次内(说是3次内,基本上就是至少需要3次,我们就按照给定的最大条件来计算,因为如果2次可以,那么3次肯定也可以)用上面的几种砝码组合,拆出100和180.

如果是3次,那么盐肯定是4堆。不过感觉上好像帮不上什么忙。上面参考的作者对问题做了数学分析,可以参考一下。

求解的话就是穷举,分别用这几种砝码组合方式拆分盐,把每次拆分的结果再递归拆分,3次之后得到拆分的所有可能,然后计算有没有符合条件的方案。

这里可以看出,第一次不管如何拆分都是偶数,因为砝码和盐堆都是偶数,怎么组合也没有奇数。

那么第二次呢?可能会出现奇数,比如用14的组合称出14g盐,14g盐平分就是7g。如果出现了奇数,按照题目是拆分成100g和180g是整数,所以就没办法拆分了,因为砝码只有偶数,如果用砝码拆分奇数,得到的会有小数,有了小数,这两堆就没办法继续了,因为再往下,小数会更多,而其他的堆没有小数,所以只能这一堆组合。如果拆分其他堆呢,因为另一堆是偶数,只能平分,也没意义,最后导致与没拆分一样。

如果第二次没有奇数,那么第三次出现奇数也只有平分,那么就不可能出现100g和180g。因为第二次比如得出盐堆a b c,a b c都是偶数,如果把a平分为a1 a2,并且是奇数,那么a1 a2没办法与b c组合,因为b c是偶数,没办法相加得出100g和180g两个偶数,所以只能a1和a2组合,那么就是要求第二次就可以得出100和180,也就是与第二步一样,与没拆分结果一样。

因为砝码和盐堆都是偶数,拆分的也是偶数,出现奇数只能平分,如果一路平分下去,那就要求第一步就直接得出了结果。因为如果只有一个偶数变成奇数,那么只能这两个奇数组合,与没拆分这一步结果一样。如果两个偶数拆分成奇数,那么要么拆分的两堆相互组合,要么内部自己组合,不管怎么组合,都是与没进行这一步结果一样。

所以拆分过程中不可能出现奇数,如果出现,就可以直接跳过了。可以帮我们减少一些计算。

我们看一下上面作者的第一种方法

#define Max_Num 5
using namespace std;
int total = 280;  //the total weight of the heap of salt
int heap1 = 100, heap2 = 180;  //the target weight of the two samll heaps of salt
int wst[] = { 0, 4, 10, 14, 18 };  //all cases of the weights combination
/* the first division result */
int x[Max_Num] = { 0 }, y[Max_Num] = { 0 };
/* the second division result */
int x1[Max_Num][Max_Num] = { {0} };
int x2[Max_Num][Max_Num] = { {0} };
int yy1[Max_Num][Max_Num] = { {0} };
int y2[Max_Num][Max_Num] = { {0} };
/* the third division result */
int x11[Max_Num][Max_Num][Max_Num] = { {{0}} }, x12[Max_Num][Max_Num][Max_Num] = { {{0}} };
int x21[Max_Num][Max_Num][Max_Num] = { {{0}} }, x22[Max_Num][Max_Num][Max_Num] = { {{0}} };
int y11[Max_Num][Max_Num][Max_Num] = { {{0}} }, y12[Max_Num][Max_Num][Max_Num] = { {{0}} };
int y21[Max_Num][Max_Num][Max_Num] = { {{0}} }, y22[Max_Num][Max_Num][Max_Num] = { {{0}} };
/** the first division, according to z=x+y, x <= y */
void weight1()
{
    int z = total;
    int k = 0, w = 0;
    for (k = 0; k < Max_Num; k++)
    {
        w = wst[k];
        x[k] = z / 2 - w;  //divide z
        y[k] = z / 2 + w;
        if (x[k] % 2 != 0)  //no need to judge y[k]
            x[k] = y[k] = 0;
    }
}
void weight2()
{
    int i = 0, k = 0, w = 0;
    for (i = 0; i < Max_Num; i++)
    {
        if (x[i] == 0)  //no need to judge y[i]
            continue;
        for (k = 0; k < Max_Num; k++)
        {
            w = wst[k];
            x1[i][k] = (x[i] - w) / 2;  //divide x
            x2[i][k] = (x[i] + w) / 2;
            if (x1[i][k] % 2 != 0)  //no need to judge x2[i][k]
                x1[i][k] = x2[i][k] = 0;
            if (x[i] == y[i])  //to avoid repeatance
                continue;
            yy1[i][k] = (y[i] - w) / 2;  //divide y
            y2[i][k] = (y[i] + w) / 2;
            if (yy1[i][k] % 2 != 0)  //no need to judge y2[i][k]
                yy1[i][k] = y2[i][k] = 0;
        }
    }
}
void weight3()
{
    int i = 0, j = 0, k = 0, w = 0;
    for (i = 0; i < Max_Num; i++)
    {
        if (x[i] == 0)  //no need to judge y[i]
            continue;
        for (j = 0; j < Max_Num; j++)
        {
            for (k = 0; k < Max_Num; k++)
            {
                w = wst[k];
                if (x1[i][j] != 0)  //divide x1[i][j]
                {
                    x11[i][j][k] = (x1[i][j] - w) / 2;
                    x12[i][j][k] = (x1[i][j] + w) / 2;
                    if (x11[i][j][k] % 2 != 0)  //x11[i][j][k] and x12[i][j][k] must be even
                        x11[i][j][k] = x12[i][j][k] = 0;
                }
                if (x2[i][j] != 0 && x1[i][j] != x2[i][j])  //divide x2[i][j], and to avoid repeatance
                {
                    x21[i][j][k] = (x2[i][j] - w) / 2;
                    x22[i][j][k] = (x2[i][j] + w) / 2;
                    if (x21[i][j][k] % 2 != 0)  //x21[i][j][k] and x22[i][j][k] must be even
                        x21[i][j][k] = x22[i][j][k] = 0;
                }
                if (yy1[i][j] != 0)  //divide yy1[i][j]
                {
                    y11[i][j][k] = (yy1[i][j] - w) / 2;
                    y12[i][j][k] = (yy1[i][j] + w) / 2;
                    if (y11[i][j][k] % 2 != 0)  //y11[i][j][k] and y12[i][j][k] must be even
                        y11[i][j][k] = y12[i][j][k] = 0;
                }
                if (y2[i][j] != 0 && yy1[i][j] != y2[i][j])  //divide y2[i][j], and to avoid repeatance
                {
                    y21[i][j][k] = (y2[i][j] - w) / 2;
                    y22[i][j][k] = (y2[i][j] + w / 2;
                    if (y21[i][j][k] % 2 != 0)  //y21[i][j][k] and y22[i][j][k] must be even
                        y21[i][j][k] = y22[i][j][k] = 0;
                }
            }
        }
    }
}
void dump_correct_results()
{
    int i = 0, j = 0, k = 0;
    for (i = 0; i < Max_Num; i++)
    {
        if (x[i] == 0)  //no need to judge y[i]
            continue;
        for (j = 0; j < Max_Num; j++)
        {
            if (x1[i][j] == 0)  //no need to judge x2[i][j]
                continue;
            for (k = 0; k < Max_Num; k++)
            {
                if (x11[i][j][k] != 0 && (x11[i][j][k] + x2[i][j] == heap1 || x12[i][j][k] + x2[i][j] == heap1))  //divide x1[i][j]
                {
                    printf("%d = %d + %d\n", total, x[i], y[i]);
                    printf("%d = %d + %d\n", x[i], x1[i][j], x2[i][j]);
                    printf("%d = %d + %d\n\n", x1[i][j], x11[i][j][k], x12[i][j][k]);
                }
            }
            for (k = 0; k < Max_Num; k++)
            {
                if (x21[i][j][k] != 0 && (x21[i][j][k] + x1[i][j] == heap1 || x22[i][j][k] + x1[i][j] == heap1))  //divide x2[i][j]
                {
                    printf("%d = %d + %d\n", total, x[i], y[i]);
                    printf("%d = %d + %d\n", x[i], x1[i][j], x2[i][j]);
                    printf("%d = %d + %d\n\n", x2[i][j], x21[i][j][k], x22[i][j][k]);
                }
            }
        }
        for (j = 0; j < Max_Num; j++)
        {
            if (yy1[i][j] == 0)  //no need to judge y2[i][j]
                continue;
            for (k = 0; k < Max_Num; k++)
            {
                if (y11[i][j][k] != 0 && (y11[i][j][k] + y2[i][j] == heap1 || y12[i][j][k] + y2[i][j] == heap1))  //divide yy1[i][j]
                {
                    printf("%d = %d + %d\n", total, x[i], y[i]);
                    printf("%d = %d + %d\n", y[i], yy1[i][j], y2[i][j]);
                    printf("%d = %d + %d\n\n", yy1[i][j], y11[i][j][k], y12[i][j][k]);
                }
            }
            for (k = 0; k < Max_Num; k++)
            {
                if (y21[i][j][k] != 0 && (y21[i][j][k] + yy1[i][j] == heap1 || y22[i][j][k] + yy1[i][j] == heap1))  //divide y2[i][j]
                {
                    printf("%d = %d + %d\n", total, x[i], y[i]);
                    printf("%d = %d + %d\n", y[i], yy1[i][j], y2[i][j]);
                    printf("%d = %d + %d\n\n", y2[i][j], y21[i][j][k], y22[i][j][k]);
                }
            }
        }
    }
}

struct MyStruct
{
    int weight;//当前是多重的盐
    int fm;//通过哪种砝码得到的
    MyStruct()
    {
        weight = 0;
        fm = 0;
    }
};
//num 已经拆分了多少次
void cf(int num, int* cfyan)
{
    if (num == 3)
    {
        if (cfyan[0] + cfyan[1] == 100 || cfyan[2] + cfyan[3] == 180)
        {
            cout << cfyan[0] << "||" << cfyan[1] << "||" << cfyan[2] << "||" << cfyan[3];
        }
        else if (cfyan[0] + cfyan[2] == 100 || cfyan[1] + cfyan[3] == 180)
        {
            cout << cfyan[0] << "||" << cfyan[2] << "||" << cfyan[1] << "||" << cfyan[3];
        }
        else if (cfyan[0] + cfyan[3] == 100 || cfyan[1] + cfyan[2] == 180)
        {
            cout << cfyan[0] << "||" << cfyan[3] << "||" << cfyan[1] << "||" << cfyan[2];
        }
    }
}
int main()
{
    int yan = 280;
    int fm[] = { 0, 4, 10, 14, 18 };
    int cfyan[] = { 0, 0, 0, 0 };
    {
        weight1();
        weight2();
        weight3();
        dump_correct_results();
    }
    char inchar;
    cin >> inchar;
}

原作者的代码有个问题,没有覆盖作者第一篇提到的,先用一个砝码称出对应的盐,然后再拆分,作者的逻辑都是平分再去掉对应的砝码重量。

 

这是上面作者的第二种解法,用链表组成树

#define Max_Num 5
#define To_Be_Devided 2
#define total 280  //the total weight of the heap of salt
int wst[] = { 0, 4, 10, 14, 18 };  //all cases of the weights combination
int heap1 = 100, heap2 = 180;  //the target weight of the two samll heaps of salt
struct Division_Node
{
    int parent_be_divided_;  //array to_be_divided_[] divided from its parent with this index
    int step_;  //the node step in the division process
    int heap_[Max_Num - 1];  //all divisions of its parent position for all weights
    int to_be_divided_[2];  //salt heap index to be divided in next step
    struct Division_Node *next_[2 * Max_Num];  //all pointers to all child divisions
    int child_;  //the numbe of children (not NULL in array next_)
};
//the root, for step 1, heap_[0] will be divided
static struct Division_Node root = { 0, 0, {total}, {0}, {NULL}, 0 };
/** the first division, according to z=x+y, x <= y */
void weight1()
{
    int div = 0, k = 0, w = 0;
    struct Division_Node *cur = &root;
    int child = 0;
    int step = 1;
    for (div = 0; div < To_Be_Devided - 1; div++)  //for step 1, only divide heap_[0]
    {
        int curpos = cur->to_be_divided_[div];
        int z = cur->heap_[curpos];  //the current heap to be divided
        for (k = 0; k < Max_Num; k++)
        {
            w = wst[k];
            int x = (z - w) / 2;  //divide z
            int y = (z + w) / 2;
            if (x % 2 != 0)  //no need to judge y[k]
                continue;
            //new a node in step 1
            struct Division_Node *node1 = (struct Division_Node*)malloc(sizeof(struct Division_Node));
            memset(node1, 0, sizeof(struct Division_Node));
            node1->parent_be_divided_ = curpos;
            node1->step_ = step;
            node1->heap_[curpos] = x;
            node1->heap_[step] = y;
            node1->to_be_divided_[0] = curpos;
            node1->to_be_divided_[1] = step;
            cur->next_[child++] = node1;  //link root and node1
        }
    }
    cur->child_ = child;
}
/** the second division, according to x=x1+x2, y=y1+y2, x1<=x2, y1<=y2
  but, x and y are saved in node1->to_be_divided_[0] and node1->to_be_divided_[1].
  so, unify them to be as x.
 */
void weight2()
{
    int div = 0, i = 0, k = 0, w = 0;
    struct Division_Node *cur = &root;
    int step = 2;
    for (i = 0; i < cur->child_; i++)  //for each node1 in step1
    {
        struct Division_Node *node1 = cur->next_[i];  //step 2 will use all nodes created in step 1
        //to avoid repeatance
        int to_be_divided = To_Be_Devided;
        if (node1->heap_[node1->to_be_divided_[0]] == node1->heap_[node1->to_be_divided_[1]])
            to_be_divided--;
        int child = 0;
        for (div = 0; div < to_be_divided; div++)  //for step 2, will divide x=heap_[0], y=heap_[1] of node1
        {
            int curpos = node1->to_be_divided_[div];
            int x = node1->heap_[curpos];  //the current heap to be divided
            for (k = 0; k < Max_Num; k++)
            {
                w = wst[k];
                int x1 = (x - w) / 2;  //divide x or y, use x in order to be in a uniform
                int x2 = (x + w) / 2;
                if (x1 % 2 != 0)  //no need to judge x2
                    continue;
                //new a node in step 2
                struct Division_Node *node2 = (struct Division_Node*)malloc(sizeof(struct Division_Node));
                memset(node2, 0, sizeof(struct Division_Node));
                memcpy(node2->heap_, node1->heap_, (Max_Num - 1) * sizeof(int));  //copy from its parent
                node2->parent_be_divided_ = curpos;
                node2->step_ = step;
                node2->heap_[curpos] = x1;
                node2->heap_[step] = x2;
                node2->to_be_divided_[0] = curpos;
                node2->to_be_divided_[1] = step;
                node1->next_[child++] = node2;  //link current node1 and node2
            }
        }
        node1->child_ = child;
    }
}
/** the third division, according to
  x1=x11+x12, y1=y11+y12, x11<=x12, y11<=y12
  x2=x21+x22, y2=y21+y22, x21<=x22, y21<=y22
  but, x1 or x2 or y1 or y2 is saved in heap_ of each node2 with index node2->to_be_divided_[0]
  and node2->to_be_divided_[1]. so, unify them to be as x1.
 */
void weight3()
{
    int div = 0, i = 0, j = 0, k = 0, w = 0;
    struct Division_Node *cur = &root;
    int step = 3;
    for (i = 0; i < cur->child_; i++)  //for each node1 in step1
    {
        struct Division_Node *node1 = cur->next_[i];
        for (j = 0; j < node1->child_; j++)  //for each node2 of node1 in step2
        {
            struct Division_Node *node2 = node1->next_[j];
            //to avoid repeatance
            int to_be_divided = To_Be_Devided;
            if (node2->heap_[node2->to_be_divided_[0]] == node2->heap_[node2->to_be_divided_[1]])
                to_be_divided--;
            int child = 0;
            for (div = 0; div < to_be_divided; div++)  //for step 3, will divide x1=heap_[0], x2=heap_[2] of node2
            {
                int curpos = node2->to_be_divided_[div];
                int x1 = node2->heap_[curpos];  //the current heap to be divided, x1, or x2, or y1, or y2
                for (k = 0; k < Max_Num; k++)
                {
                    w = wst[k];
                    int x11 = (x1 - w) / 2;  //divide x or y, use x in order to be in a uniform
                    int x12 = (x1 + w) / 2;
                    if (x11 % 2 != 0)  //no need to judge x12
                        continue;
                    //new a node in step 3
                    struct Division_Node *node3 = (struct Division_Node*)malloc(sizeof(struct Division_Node));
                    memset(node3, 0, sizeof(struct Division_Node));
                    memcpy(node3->heap_, node2->heap_, (Max_Num - 1) * sizeof(int));  //copy from its parent
                    node3->parent_be_divided_ = curpos;
                    node3->step_ = step;
                    node3->heap_[curpos] = x11;
                    node3->heap_[step] = x12;
                    node3->to_be_divided_[0] = curpos;  //in fact, this array in step3 needed for dump
                    node3->to_be_divided_[1] = step;
                    node2->next_[child++] = node3;  //link current node2 and node3
                }
            }
            node2->child_ = child;
        }
    }
}
void dump_correct_results(struct Division_Node* node)
{
    int i = 0, j = 0, k = 0;
    struct Division_Node *cur = node;
    for (i = 0; i < cur->child_; i++)  //for each node1 in step1
    {
        struct Division_Node *node1 = cur->next_[i];
        for (j = 0; j < node1->child_; j++)  //for each node2 of node1 in step2
        {
            struct Division_Node *node2 = node1->next_[j];
            for (k = 0; k < node2->child_; k++)  //for each node3 of node2 in step 3
            {
                struct Division_Node *node3 = node2->next_[k];
                /** unify them into the following equations
                  z = x + y, x <= y
                  x = x1 + x2, x1 <= x2
                  x1 = x11 + x12, x11 <= x12
                 */
                int x11 = node3->heap_[node3->to_be_divided_[0]];
                int x12 = node3->heap_[node3->to_be_divided_[1]];
                int x2index = 0;
                if (node3->parent_be_divided_ == node2->to_be_divided_[0])
                    x2index = node2->to_be_divided_[1];
                else
                    x2index = node2->to_be_divided_[0];
                int x2 = node2->heap_[x2index];
                if (x11 + x2 == heap1 || x12 + x2 == heap1)
                {
                    printf("%d = %d + %d\n", total, node1->heap_[node1->to_be_divided_[0]],
                        node1->heap_[node1->to_be_divided_[1]]);
                    printf("%d = %d + %d\n", node1->heap_[node2->parent_be_divided_],
                        node2->heap_[node2->to_be_divided_[0]],
                        node2->heap_[node2->to_be_divided_[1]]);
                    printf("%d = %d + %d\n\n", node2->heap_[node3->parent_be_divided_], x11, x12);
                }
            }
        }
    }
}
void free_all_nodes(struct Division_Node* node)
{
    int i = 0, j = 0, k = 0;
    struct Division_Node *cur = node;
    for (i = 0; i < cur->child_; i++)  //for each node1 in step1
    {
        struct Division_Node *node1 = cur->next_[i];
        for (j = 0; j < node1->child_; j++)  //for each node2 of node1 in step2
        {
            struct Division_Node *node2 = node1->next_[j];
            for (k = 0; k < node2->child_; k++)  //for each node3 of node2 in step 3
            {
                struct Division_Node *node3 = node2->next_[k];
                free(node3);
            }
            free(node2);
        }
        free(node1);
    }
}
int main(/* int argc, char** argv */)
{
    weight1();
    weight2();
    weight3();
    dump_correct_results(&root);
    free_all_nodes(&root);

    char inchar;
    cin >> inchar;
}

 

我做了改进,增加了单独称出一些盐的条件,不足之处,就是有重复数据,没有判断。

int fmweight[] = { 0, 4, 10, 14, 18 };
struct MNODE
{
    vector<int> mweight;//当前拆分的盐堆
    vector<MNODE*> mnext;//当前盐堆对应的拆分
};
void devsalt(MNODE* pnode)
{
    if (pnode->mweight.size() == 4)
    {
        if (pnode->mweight[0] + pnode->mweight[1] == 100)
        {
            cout << pnode->mweight[0] << " " << pnode->mweight[1] << "||" << pnode->mweight[2] << " " << pnode->mweight[3] << endl;
        }
        else if (pnode->mweight[0] + pnode->mweight[2] == 100)
        {
            cout << pnode->mweight[0] << " " << pnode->mweight[2] << "||" << pnode->mweight[1] << " " << pnode->mweight[3] << endl;
        }
        else if (pnode->mweight[0] + pnode->mweight[3] == 100)
        {
            cout << pnode->mweight[0] << " " << pnode->mweight[3] << "||" << pnode->mweight[1] << " " << pnode->mweight[2] << endl;
        }
        else if (pnode->mweight[1] + pnode->mweight[2] == 100)
        {
            cout << pnode->mweight[1] << " " << pnode->mweight[2] << "||" << pnode->mweight[0] << " " << pnode->mweight[3] << endl;
        }
        else if (pnode->mweight[1] + pnode->mweight[3] == 100)
        {
            cout << pnode->mweight[1] << " " << pnode->mweight[3] << "||" << pnode->mweight[0] << " " << pnode->mweight[2] << endl;
        }
        else if (pnode->mweight[2] + pnode->mweight[3] == 100)
        {
            cout << pnode->mweight[2] << " " << pnode->mweight[3] << "||" << pnode->mweight[0] << " " << pnode->mweight[1] << endl;
        }
    }
    else
    {
        for (int i = 0; i < pnode->mweight.size(); i++)
        {
            for (int j = 0; j < 5; j++)
            {
                {
                    int x = (pnode->mweight[i] - fmweight[j]) / 2;
                    int y = (pnode->mweight[i] + fmweight[j]) / 2;
                    if (x % 2 == 0)
                    {
                        MNODE* tnode = new MNODE;
                        for (int p = 0; p < pnode->mweight.size(); p++)
                        {
                            if (p != i)
                            {
                                tnode->mweight.emplace_back(pnode->mweight[p]);
                            }
                        }
                        tnode->mweight.emplace_back(x);
                        tnode->mweight.emplace_back(y);
                        pnode->mnext.emplace_back(tnode);
                        devsalt(tnode);
                    }
                }
                if(fmweight[j] > 0)
                {
                    int x = pnode->mweight[i] - fmweight[j];
                    int y = fmweight[j];
                    if (x > 0 && x % 2 == 0)
                    {
                        MNODE* tnode = new MNODE;
                        for (int p = 0; p < pnode->mweight.size(); p++)
                        {
                            if (p != i)
                            {
                                tnode->mweight.emplace_back(pnode->mweight[p]);
                            }
                        }
                        tnode->mweight.emplace_back(x);
                        tnode->mweight.emplace_back(y);
                        pnode->mnext.emplace_back(tnode);
                        devsalt(tnode);
                    }
                }
            }
        }
    }
}
int main()
{
    MNODE* phead = new MNODE;
    phead->mweight.emplace_back(280);
    devsalt(phead);
    char inchar;
    cin >> inchar;
}

虽然增加了单独称出某些盐的方法,但是并没有增加结果,因为如果单独称出某些盐,这道题只能是利用已知的盐堆,这样的话,情况更多,这里就没有处理。别忘了释放内存。

 

砝码称重3

标签:http   无限   out   visio   没有   ted   tail   mys   重复数   

原文地址:https://www.cnblogs.com/studywithallofyou/p/12120992.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!