1. Let's talk about the sequence queue to establish the data structure.
/*************************************** * ********************************* Ordered queue (cyclic queue) implement the FIFO branch restriction method-the loading problem changes the data structure and only replaces the previous chain queue with the cyclic queue. The remaining functions are basically not changed, and the main () function is not changed at all, but enqueue (), add (), dequeue () some function parameters in functions involving e and Beste are changed from the queue * type to the int type. The parameters in the function call are not changed at all. In the original chain queue program, the data structure is defined by node. Each node contains * parent, weigth, lchild, * next. Then, a queue contains many nodes. Each time you join or exit a queue, E and Beste are independent by adding or deleting nodes that contain these elements, nodes of the preceding type do not depend on the Link queue's SCSI. Each time a node address is used to store the addresses of some nodes, you can call * parent, weigth, lchild and other elements, which are implemented by the blockchain queue. Here, I use cyclic queues for implementation. Ordered queues and cyclic queues are both sequential storage methods. The data to be stored will be stored in an array (arrays are sequential ). Therefore, the idea is different from the previous implementation of the chain queue. In the past, each node had a parent, weight, lchild, but now there is only one node sq. Element search is based on the lower mark value, which is equivalent to the node address in the simulation chain queue. This lower mark value can be simulated as an address. So, weight, parent, and lchild each have an array weight [], parent [], lchild []; for example, e-> weight in the chain queue indicates the weight of the node pointed to by E. in the loop queue, weight [e] is used. In the chain queue, E is of the queue * type, indicating the type of the queue node. However, in the ordered queue, it is defined as the int type, indicating the lower value, start from 1 (0 indicates that when the weight value of an empty node is-1 ). For example, bestx [J] = Beste-> lchild; Beste = Beste-> parent; in the original chain queue program is replaced with the following: bestx [J] = Q-> lchild [Beste]; Beste = Q-> parent [Beste]; so, let's take a closer look at the differences between the two methods. In fact, there is also a way to build a data structure, which is also a cyclic queue or an ordered queue, which always uses arrays to store elements. But that method is basically the same as the idea of the chain queue. The only difference between nodes in the chain queue is that the nodes in the chain queue are not sequential, but are connected by pointers, this method does open up an ordered Node space Q [100]; see the following struct {int weight; int lchild; int parent;} Q [maxsize]; int front, int rear; this is basically the same as the chain queue method. Weight, lchild, and parent are all elements inside the node. Front and rear are independent elements used to point to nodes. Carefully understand the similarities and differences between the three queuing construction methods. **************************************** ***************************************/ # Include <stdio. h> # include <stdlib. h ># definemaxsize100typedef struct {int weight [maxsize]; int lchild [maxsize]; int parent [maxsize]; int front, rear;} sequeue; // There are only global variables: * bestx and bestw. Int * bestx; int bestw = 0; // The current optimal void initqueue (sequeue * sq) {SQ-> front = SQ-> rear = 0; for (INT I = 0; I <maxsize; I ++) {SQ-> parent [I] =-1 ;}} int empty (sequeue * sq) {If (SQ-> rear = SQ-> front) return 1; elsereturn 0;} int add (sequeue * SQ, int W, int e, int L) {If (SQ-> rear + 1) % maxsize = SQ-> front) {printf ("the queue is full! \ N "); Return 0;} SQ-> rear = (SQ-> rear + 1) % maxsize; SQ-> weight [SQ-> rear] = W; SQ-> lchild [SQ-> rear] = L; SQ-> parent [SQ-> rear] = E; return 1;} int dequeue (sequeue * SQ, int * E) {If (empty (SQ) {printf ("the queue is empty! \ N "); Return 0;} SQ-> front = (SQ-> front + 1) % maxsize; * E = SQ-> front; return 1 ;} void enqueue (sequeue * SQ, int wt, int I, int N, int e, int * Beste, int ch) {if (I = N) {If (Wt = bestw) {* Beste = E; // Beste is used only when I = N, that is, when the leaf is used, because in order to trace the path, beste = Beste-> parent; that is to say, once the leaf node is reached, the bestx [N] = CH;} return ;}add (SQ, wt, E, CH) has been searched ); // not leaf}/* int getheadqueue (sequeue * SQ, int * X) {If (empty (SQ) {printf ("the queue is empty! \ N "); Return 0;} * x = SQ-> data [(SQ-> front + 1) % maxsize]; return 1 ;} */INT maxloading (int w [], int C, int N) // calculate the maximum loading function {int err; // return value: int I = 1; // The layer int CNT of the current expansion node = 0; int ew = 0; // the weight of the current expansion node int r = 0; // The remaining container weight int flag = 0; int e = 0; int Beste = 0; sequeue * q = (sequeue *) malloc (sizeof (sequeue); // live node queue for (Int J = 2; j <= N; j ++) {R + = W [J];} bestw = 0; // The current optimal initqueue (Q); err = add (Q, -1, 0, 0); If (! Err) {return 0;} while (true) {int Wt = ew + W [I]; If (wt <= C) // check the left child node {If (wt> bestw) bestw = wt; // X [I] = 1 enqueue (Q, ew + W [I], I, n, e, & Beste, 1); flag = 1;/****** this part of the pruning content can also be placed in this, of course, only if (! Flag), but no else *** if (EW + r> = bestw & I <n) // pruning the right child {enqueue (Q, ew, I, n, E, & Beste, 0);} ********/} // If (! Flag) // if the flag is equal to 0, it indicates that the left child is not in the queue, so the right child must be in the queue. It makes sense logically. {Enqueue (Q, ew, I, n, E, & Beste, 0);} else {If (EW + r> bestw & I <n) // trim the right child {enqueue (Q, ew, I, n, E, & Beste, 0);} flag = 0; // I forgot to clear the flag. It took me a long time to check it. I thought it was an algorithm error. In fact, I thought the algorithm was correct, I just forgot to clear it. // That is to say, if this flag is not cleared, then every time if (! Flag) The {} else {} program will execute else, that is to say, every time the program is regarded as having left children in the queue (flag = 1 ), so as to determine the pruning condition // if the condition is not met, the right child is not in the queue. In this case, the left and right children are not in the queue. But in fact, the logic is not clear. If the left child is not in the queue, the right child must be in the queue, because the left child is in the queue. // indicates that W [I] is selected. if wt <= C is not met and the left branch is not selected, this item is not selected, the meaning of the right child's team is of course not to select this item W [I], so if the left child is not in the team, // The right child must be in the team. So, the logic of the program is: first check the left child, if wt <= C, the left child enters the team, flag set. Then use the if statement and flag if (! Flag) {} else {} to judge. If flag = 0, the left child is not in the queue (item W [I] is not selected, the right child must be in the queue, so the right child is in the queue. However, if the flag is equal to or equal to 1, it indicates that the previous left child has met the conditions and has joined the team. In this case, the current value of the right subtree (EW) + the remaining maximum quality (the sum of the values of all left subtree after the right subtree, that is, R) Whether to> the current optimal bestw // (bestw is generally the value of the Left node at the same level of the current right subtree). If it is not greater, it indicates that the number of Subtrees in the lower level of this level is not as big as the current value bestw even if all the left subtree (each item is required). Therefore, this right subtree is unnecessary, therefore, the right subtree is judged to be trimmed (if conditions are met, the right child is not trimmed, And the right child enters the queue ).} Dequeue (Q, & E); If (E! = 0 & Q-> weight [e] =-1) // I think this place is e! = NULL is useless. If (e-> Weight =-1) is used directly. {// If (empty (q) {break ;} if (I <n) {Add (Q,-1, 0, 0); // end of the same layer node} dequeue (Q, & E); I ++; // enter the next layer R-= W [I];} ew = Q-> weight [E];} For (Int J = n-1; j> 0; j --) // construct the current optimal solution {bestx [J] = Q-> lchild [Beste]; Beste = Q-> parent [Beste];} return 0;} int main () {int n = 0; int C = 0; int I = 0; int * w; file * In, * out; in = fopen ("input4.txt", "R "); if (in = NULL) {printf ("no input/output file \ n"); return 1;} fscanf (in, "% d", & N ); fscanf (in, "% d", & C); W = (int *) malloc (sizeof (INT) * (n + 1); bestx = (int *) malloc (sizeof (INT) * (n + 1); for (I = 1; I <= N; I ++) {fscanf (in, "% d ", & W [I]);} maxloading (W, C, N); out = fopen ("output.txt", "W"); for (I = 1; I <= N; I ++) {fprintf (Out, "% d \ t", bestx [I]);} fprintf (Out, "\ n "); fclose (in); fclose (out); Return 0 ;}
Ii. Let's talk about how to establish a data structure in a chain queue.
/*************************************** * ******************* Dual pointer to solve the FIFO queue Loading Problem v0.3, all use local variables + double pointer + Regular familiar queue construction method + correct pruning algorithm input: Enter N, C, W [1] In input.txt, W [2],..., W [N]. Output: output to bestx [1], bestx [2],..., in output.txt. bestx [N] indicates that W [I] is selected. Data Structure: queue. The custom queue-Type Universal queue implementation method is applied, and personalized processing is flexibly implemented, such as * parent, lchild and other ************************************** * **********************/# include <stdio. h> # include <stdlib. h> typedef struct qnode {struct qnode * parent; // pointer to the parent node struct qnode * Next; int lchild; // The left son flag int weight; // weight of the node} qtype;/* Note: Use qtype to define * E and * Beste, because both E and Beste are of the qtype type, you do not need to define a linkqueue type. E and Beste are independent nodes, which have no direct relationship with Q of linkqueue * q. They do not depend on Q and are free, but front and rear are defined in linkqueue, although it is of the qtype type, it depends on Q. Q-> front, Q-> rear. */typedef struct {// qtype * front, * rear;} linkqueue; // there are only two global variables: * bestx and bestw. Int * bestx; int bestw = 0; // The current optimal value int initqueue (linkqueue * SCSI) // initialize the queue {qtype * P; P = (qtype *) malloc (sizeof (qtype); If (! P) {printf ("failed to allocate space! \ N "); Return 0;} p-> next = NULL; P-> Weight =-1; p-> parent = NULL; SCSI-> front = SCSI-> rear = P; return 1;} int add (linkqueue * SCSI, int W, qtype * E, int L) // queue atomic operation {qtype * q; q = (qtype *) malloc (sizeof (qtype); If (! Q) {printf ("failed to allocate space! \ N "); Return 0;} Q-> Weight = W; // Q-> next = NULL; q-> parent = E; // Q-> lchild = L; // SCSI-> rear-> next = Q; SCSI-> rear = Q; return 1;} int isempty (linkqueue * SCSI) // judge whether the right is null {return (SCSI-> front = SCSI-> rear? 1-0);}/* out of the queue. The Node pointer of the out of the queue is assigned to * E, and the passed parameter */INT Delete (linkqueue * SCSI, qtype ** E) is modified using the double pointer) {qtype * TMP = NULL; If (isempty (SCSI) {printf ("Team blank! \ N "); Return 0;} TMP = SCSI-> front-> next; SCSI-> front-> next = TMP-> next; if (SCSI-> front-> next = NULL) SCSI-> rear = SCSI-> front; * E = TMP; // free (TMP); return 1 ;} /* The encapsulation operation of the queue uses the double pointer to modify the passed parameter */void enqueue (linkqueue * SCSI, int wt, int I, int N, qtype * E, qtype ** Beste, int ch) {if (I = N) {If (Wt = bestw) {* Beste = E; // Beste only when I = n, beste is used only when the leaves are located. Because the trace path is/, Beste = Beste-> parent is used. // That is to say, once a leaf node is reached, it indicates that the search has ended. bestx [N] = CH;} return;} Add (SCSI, Wt, E, CH); // not leaf} int maxloading (int w [], int C, int N) // evaluate the Maximum Loading Function {int err; // return value int I = 1; // The layer int CNT of the current extension node = 0; int ew = 0; // the weight of the current extension node int r = 0; // remaining container weight int flag = 0; linkqueue * q = (linkqueue *) malloc (sizeof (linkqueue); // live node queue qtype * E = NULL; qtype * Beste = NULL; For (Int J = 2; j <= N; j ++) {R + = W [J];} bestw = 0; // The current optimal value initqueue (Q); err = add (Q,-1, null, 0); If (! Err) {return 0;} while (true) {int Wt = ew + W [I]; If (wt <= C) // check the left child node {If (wt> bestw) bestw = wt; // X [I] = 1 enqueue (Q, ew + W [I], I, n, e, & Beste, 1); flag = 1;/*** this part of the pruning content can also be placed in it. Of course, only if (! If (EW + r> = bestw & I <n) // pruning the right child {enqueue (Q, ew, I, n, e, & Beste, 0) ;}**********/} // If (! Flag) // if the flag is equal to 0, it indicates that the left child is not in the queue, so the right child must be in the queue. It is logical to make sense only when the reason is. {Enqueue (Q, ew, I, n, E, & Beste, 0);} else {If (EW + r> bestw & I <n) // trim the right child {enqueue (Q, ew, I, n, E, & Beste, 0);} flag = 0; // I forgot to clear the flag. It took me a long time to check it. I thought it was an algorithm error. In fact, I thought the algorithm was correct, I just forgot to clear it. // That is to say, if this flag is not cleared, then every time if (! Flag) The {} else {} program will execute // else, that is, every time the program is used as having left children in the queue (flag = 1 ), then, determine the pruning condition // if the condition is not met, the right child will not join the team. In this case, the left and right children will not join the team. But in fact, the logic is not clear. If the left child is not in the queue, the right child must be in the // team. Because the left child is in the queue, W [I] is selected. if wt <= C is not met and the left branch is not selected, // If the left branch is not selected, this item is not selected, the meaning of the right child's team is of course not to select this/item W [I]. Therefore, if the left child is not in the team, the right child must be in the team. So, the logic of the program // is: first check the left child, if wt <= C, the left child enters the team, flag set. Then use the if // statement and flag if (! Flag) {} else {} to judge. If flag = 0, it means that the left child is not in the queue (things/product w [I] is not selected). Since it is not selected, the right child must be in the queue, so the right child is in the queue. // However, if the flag is equal to or equal to 1, it indicates that the previous left child has met the conditions and is already in the queue. In this case, // check the current value (EW) of the right subtree if the right child is in the queue or not) + residual maximum quality (the sum of all left subtree values after this right // subtree, that is, R) whether it is> current optimal value // bestw (bestw is generally the value of the Left node at the same level of the current right subtree). If it is not // greater, it indicates that the number of Subtrees in the lower level of this level is not as big as the current value bestw even if all the left subtree (each item is required). Therefore, this right subtree is unnecessary, therefore, the right subtree is split into/rows to determine the pruning. (if the conditions in the IF condition are met, no pruning is performed. The right subtree is added to the queue ).} Delete (Q, & E); If (E! = NULL & E-> Weight =-1) // I think this place is e! = NULL is useless. // If (e-> Weight =-1) can be used directly. {// If (isempty (q) {break ;} if (I <n) {Add (Q,-1, null, 0); // end of the same layer node} Delete (Q, & E); I ++; // enter the next layer R-= W [I];} ew = e-> weight;} For (Int J = n-1; j> 0; j --) // construct the current optimal solution {bestx [J] = Beste-> lchild; Beste = Beste-> parent;} return 0 ;}int main () {int n = 0; int C = 0; int I = 0; int * w; file * In, * out; in = fopen ("input.txt", "R "); if (in = NULL) {printf ("no input/output file \ n"); return 1;} fscanf (in, "% d", & N ); fscanf (in, "% d", & C); W = (int *) malloc (sizeof (INT) * (n + 1); bestx = (int *) malloc (sizeof (INT) * (n + 1); for (I = 1; I <= N; I ++) {fscanf (in, "% d ", & W [I]);} maxloading (W, C, N); out = fopen ("output.txt", "W"); for (I = 1; I <= N; I ++) {fprintf (Out, "% d \ t", bestx [I]);} fprintf (Out, "\ n "); fclose (in); fclose (out); Return 0 ;}
III.
Running result:
In input.txt, enter n = 4, C = 70, W1 = 30, W2 = 25, W3 = 15, W4 = 10.
View the running result in output.txt:
This 1 1 1 0 is the result of bestx [I]. bestx [I] = 1 indicates that this branch is selected, that is, the I goods are loaded. 0 indicates that the goods are not loaded.