lp_solve 解决 1D 背包问题

本文提供了一个使用C语言实现的程序,该程序采用贪婪算法初始化解,然后通过第一下降法或最佳下降法进行局部搜索优化,以解决0-1背包问题。程序首先计算物品价值/重量比例并排序,接着执行局部搜索策略寻找更优解,并最终输出优化后的解决方案。
摘要由CSDN通过智能技术生成
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

// global parameteres
int MAX_NUM_OF_ITERS = 100;
int MAX_TIME = 30; //max 30 sec comp time.
int NB_METHOD=1; //0: first descent 1: best descent

/*The following is problem data. For convenience, we
include in the program. For real applications, the data
should be loaded from file(s).*/
int NUM_OF_ITEMS=100;  //
int CAPACITY=1000;

int p[] = {11, 11, 10, 12, 3, 5, 13, 6, 10, 12, 19, 8, 3, 19, 3, 7, 8, 17, 8, 3, 5, 3, 5, 5, 13, 9, 9, 4, 11, 20, 18, 5, 17, 19, 14, 4, 14, 7, 17, 6, 9, 7, 12, 20, 3, 9, 12, 4, 7, 13, 20, 3, 18, 4, 12, 10, 3, 20, 4, 4, 13, 17, 16, 4, 5, 16, 18, 8, 18, 20, 9, 10, 10, 16, 18, 20, 3, 5, 17, 16, 13, 11, 3, 10, 20, 12, 6, 6, 11, 18, 18, 14, 19, 6, 18, 9, 14, 12, 10, 19};

int v[] = {93, 108, 82, 67, 82, 88, 77, 60, 138, 135, 93, 92, 128, 134, 144, 75, 148, 133, 150, 103, 79, 82, 106, 143, 99, 101, 80, 90, 84, 62, 90, 95, 119, 75, 101, 93, 85, 118, 81, 64, 87, 113, 117, 142, 88, 134, 134, 100, 112, 103, 90, 149, 122, 145, 92, 63, 103, 140, 62, 138, 60, 103, 145, 143, 109, 117, 63, 65, 124, 78, 121, 114, 96, 99, 110, 125, 95, 92, 70, 70, 149, 115, 148, 85, 81, 62, 99, 124, 91, 101, 118, 130, 140, 86, 97, 138, 89, 63, 122, 112 };


// 每个对象的具体元素
struct item{
    int indx;   // 排序后记住索引
    int p;
    int v;
    double ratio;
};
struct problem{
    int C;              // int CAPACITY=1000;
    int num_of_items;   // int MAX_NUM_OF_ITERS = 100;
    struct item* items;
};
struct solution{
    int objective;
    int cap_left;
    struct problem* prob;
    int* x;
};

// 对问题初始化,赋变量
struct problem* init_prob(){
    struct item* my_item = malloc(sizeof(struct item)*NUM_OF_ITEMS);
    for(int i=0; i<NUM_OF_ITEMS; i++){
        my_item[i].indx=i;
        my_item[i].p=p[i];
        my_item[i].v=v[i];
    }
    struct problem* my_prob = malloc(sizeof(struct problem));
    my_prob->C =CAPACITY;
    my_prob->num_of_items = NUM_OF_ITEMS;
    my_prob->items = my_item;
    return my_prob;
}

// 用来清空内存
void free_problem(struct problem* my_prob) {
    if(my_prob!=NULL){
        free(my_prob->items); //free item array
        free(my_prob);
    }
}

//create an empty solution
struct solution* create_empty_sol(struct problem* my_prob) {
    struct solution* my_sln = malloc(sizeof(struct solution));
    my_sln->prob = my_prob;
    my_sln->objective=0; my_sln->cap_left=my_prob->C;
    my_sln->x = malloc(sizeof(int)*my_prob->num_of_items);
    for(int i=0; i<my_prob->num_of_items; i++) my_sln->x[i]=0;
    return my_sln;
}

struct solution* copy_from(struct solution* sln){
    struct solution* my_sln = malloc(sizeof(struct solution));
    my_sln->prob = sln->prob;  //shalow copy
    my_sln->objective=sln->objective; my_sln->cap_left=sln->cap_left;
    my_sln->x = malloc(sizeof(int)*sln->prob->num_of_items);
    for(int i=0;i<sln->prob->num_of_items; i++)
        my_sln->x[i] = sln->x[i];
    return my_sln;
}

// 用来清空内存
void free_solution(struct solution* sln){
    if(sln!=NULL){
        free(sln->x);
        free(sln);
    }
}

void print_sol(struct solution* sln, char* sol_name){
    printf("%s's objective = %d, cap left = %d\n",sol_name, sln->objective, sln->cap_left);
    
    //checking anormaly in the solution struct.
    int cap=0, obj=0;
    for(int i=0; i<sln->prob->num_of_items; i++){
        if(sln->x[sln->prob->items[i].indx]>0){
            obj += sln->prob->items[i].p;
            cap +=sln->prob->items[i].v;
        }
    }
    if(obj != sln->objective) {
        printf("Inconsistent objective value. Correct val = %d\n", obj);
    }
    if(sln->prob->C - cap != sln->cap_left){
        printf("Inconsistent residual capacity value. Correct val =%d\n",
               sln->prob->C- cap);
    }
        
}

int cmpfunc (const void * a, const void * b) {
    const struct item* item1 = a;
    const struct item* item2 = b;
    if(item1->ratio>item2->ratio) return -1;
    if(item1->ratio<item2->ratio) return 1;
    return 0;
}
int cmpfunc2 (const void * a, const void * b) {
    const struct item* item1 = a;
    const struct item* item2 = b;
    if(item1->indx>item2->indx) return 1;
    if(item1->indx<item2->indx) return -1;
    return 0;
}


// !!!!!!!!!! ↓
//greedy heuristic by packing highest pi/vi
struct solution* greedy_heuristic(struct problem* prob){
    
    if(prob==NULL){       // 检查问题是否存在
        printf("Missing problem data, please check!\n");
        exit(1);
    }
    struct solution* greedy_sln =create_empty_sol(prob);   // 建立 solution
    int n = prob->num_of_items;
    for(int i=0;i<n; i++){
        prob->items[i].ratio = (double)prob->items[i].p/prob->items[i].v;
        //printf("ratio[%d]=%.3f\t",prob->items[i].indx,prob->items[i].ratio);
    }
    //sort items according to ratio
    qsort(prob->items, n, sizeof(struct item), cmpfunc);
    greedy_sln->cap_left=prob->C; greedy_sln->objective=0;
    for(int i=0;i<n; i++){
        //printf("ratio[%d]=%.3f\t",prob->items[i].indx,prob->items[i].ratio);
        if(greedy_sln->cap_left>= prob->items[i].v){
            greedy_sln->x[prob->items[i].indx]=1;
            greedy_sln->cap_left -= prob->items[i].v;
            greedy_sln->objective += prob->items[i].p;
        }
    }
    //make sure original order to items is restored to match index in x
    qsort(prob->items, n, sizeof(struct item), cmpfunc2);
    //print_sol(greedy_sln, "Greedy Solution");
    return greedy_sln;
}


// Fist fit
struct solution* first_descent(struct solution* curt_sln) {  //使用配对交换
    int item1, item2;
    struct solution* new_sln = copy_from(curt_sln);   // 引入 original solution
    for(int i=0; i<NUM_OF_ITEMS; i++) {
        if(curt_sln->x[i]>0){   // 如果当前的 x_i 解 在背包里
          item1 =i;
          for(int j=0; j<NUM_OF_ITEMS; j++){  // 搜索是否有其他更适合的值
           int v1 = curt_sln->prob->items[item1].v;  // 遍历时当前的一个 item 的 volumn 
              int v2 = curt_sln->prob->items[j].v;  // 每一个 item 的 volumn
          if(i!=j && curt_sln->x[j]==0 && curt_sln->cap_left + v1 >= v2) {  // x_i 加进来后还有剩余 capacity
              item2=j;
              int delta =curt_sln->prob->items[item2].p -
                curt_sln->prob->items[item1].p;
              if(delta >0){
                  new_sln->x[item1]= 0;
                  new_sln->x[item2]= 1; //换 P 更大的进来
                  new_sln->objective=curt_sln->objective + delta;  //delta evaluation
                  new_sln->cap_left = new_sln->cap_left - v2 + v1;
                  //print_sol(new_sln, "First Descent Solution");
                  return new_sln;
              }
          }//endif
          }//endfor
        }//endif
    }//endfor
    return NULL;
}

// best fit
struct solution* best_descent(struct solution* curt_sln) {
    int item1, item2;
    int best_delta = -1000, b_item1=-1, b_item2=-1; //store the best move
    struct solution* new_sln = copy_from(curt_sln);
    for(int i=0; i<NUM_OF_ITEMS; i++)
    {
        if(curt_sln->x[i]>0){  // 同上
          item1 =i;
          for(int j=0; j<NUM_OF_ITEMS; j++){
              int v1 = curt_sln->prob->items[item1].v;
              int v2 = curt_sln->prob->items[j].v;
              if(i!=j && curt_sln->x[j]==0 && curt_sln->cap_left + v1 >= v2) {
                  item2=j;
                  int delta =curt_sln->prob->items[item2].p -
                    curt_sln->prob->items[item1].p;
                  if(delta >0 && delta>best_delta){
                      b_item1 = item1; 
                      b_item2 = item2;
                      best_delta= delta;     // x_i 和 x_j 的差值
                  }
              }
          }//endfor
        }//endif
    }//endfor
    if(best_delta>0){
        new_sln->x[b_item1]= 0;
        new_sln->x[b_item2]= 1; //swap
        new_sln->objective=curt_sln->objective + best_delta;  
        	//delta:x_i 和 x_j 交换后 p 的差值;objective:目标函数值
        int v1 = curt_sln->prob->items[b_item1].v;
        int v2 = curt_sln->prob->items[b_item2].v;
        new_sln->cap_left = new_sln->cap_left - v2 + v1;
        //print_sol(new_sln, "Best Descent Solution");
        return new_sln;
    }
    else
        return NULL;
}
    
struct solution* local_search(struct solution* init_sln, int nb_method){
    struct solution *nb_sln, *curt_sln;
    curt_sln = copy_from(init_sln);
    for(int k=0; k< MAX_NUM_OF_ITERS; k++)
    {
         if(NB_METHOD==0)
             nb_sln=first_descent(curt_sln);  //first descent local search
         else nb_sln=best_descent(curt_sln);  //best descent local sarch
         if(nb_sln!=NULL)
         {
             free_solution(curt_sln);
             curt_sln= copy_from(nb_sln);
             free_solution(nb_sln);
         }
    }
    return curt_sln;
}



int main()
{
    //problem* prob = loaddata("knapsack.txt");
    struct problem* prob = init_prob();
	
	// original solution
    struct solution* init_sln = greedy_heuristic(prob);  // 贪婪算法
    print_sol(init_sln,"Initial Solution");
    
    // local optimasation solution
    struct solution *local_optimum_sln;
    local_optimum_sln = local_search(init_sln, NB_METHOD); //local search
    print_sol(local_optimum_sln, "Local Optima Solution");

    //free memory for all pointers
    free_problem(prob);
    free_solution(init_sln);
    free_solution(local_optimum_sln);
    return 0;


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值