1. 程式人生 > >01揹包問題 -- 回溯法 1

01揹包問題 -- 回溯法 1

/*0-1揹包回溯法實現*/
#include <stdio.h>
#include <conio.h>
int n;				//物品數量
double c;			//揹包容量
double v[100];		//各個物品的價值
double w[100];		//各個物品的重量
double cw = 0.0;		//當前揹包重量
double cp = 0.0;		//當前揹包中物品價值
double bestp = 0.0;	//當前最優價值
double perp[100];	//單位物品價值排序後
int order[100];		//物品編號
int put[100];			//設定是否裝入
/*按單位價值排序*/
void knapsack()
{
    int i,j;
    int temporder = 0;
    double temp = 0.0;
    for(i=1;i<=n;i++)
        perp[i]=v[i]/w[i];
    for(i=1;i<=n-1;i++)
    {
        for(j=i+1;j<=n;j++)
            if(perp[i]<perp[j]) //氣泡排序perp[],order[],sortv[],sortw[]
        {
            temp = perp[i];
            perp[i]=perp[i];
            perp[j]=temp;
            temporder=order[i];
            order[i]=order[j];
            order[j]=temporder;
            temp = v[i];
            v[i]=v[j];
            v[j]=temp;
            temp=w[i];
            w[i]=w[j];
            w[j]=temp;
        }
    }
}
/*回溯函式*/
void backtrack(int i)
{
    double bound(int i);
    if(i>n)
    {
        bestp = cp;
        return;
    }
    if(cw+w[i]<=c)
    {
        cw+=w[i];
        cp+=v[i];
        put[i]=1;
        backtrack(i+1);
        cw-=w[i];
        cp-=v[i];
    }
    if(bound(i+1)>bestp)  //符合條件搜尋右子數
        backtrack(i+1);
}
/*計算上界函式*/
double bound(int i)
{
    double leftw= c-cw;
    double b = cp;
    while(i<=n&&w[i]<=leftw)
    {
        leftw-=w[i];
        b+=v[i];
        i++;
    }
    if(i<=n)
        b+=v[i]/w[i]*leftw;
    return b;
}
int main()
{
    int i;
    printf("請輸入物品的數量和容量:");
    scanf("%d %lf",&n,&c);
    printf("請輸入物品的重量和價值:\n");
    for(i=1;i<=n;i++)
    {
        printf("第%d個物品的重量:",i);
        scanf("%lf",&w[i]);
        printf("價值是:");
        scanf("%lf",&v[i]);
        order[i]=i;
    }
    knapsack();
    backtrack(1);
    printf("最優價值為:%lf\n",bestp);
    printf("需要裝入的物品編號是:");
    for(i=1;i<=n;i++)
    {
        if(put[i]==1){
            printf("%d ",order[i]);	
		}
    }
	printf("\n");
   return 0;
}