1. 程式人生 > >01揹包問題(用c語言實現)-回溯法求解

01揹包問題(用c語言實現)-回溯法求解

回溯法求解01揹包

  用回溯法解問題時,應明確定義問題的解空間。問題的解空間至少應包含問題的一個(最優)解。例如,對於有n種可選擇物品的0-1揹包問題,其解空間由長度為n的0-1向量組成。該解空間包含對變數的所有可能的0-1賦值。當n=3時,其解空間是{(0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1)} 定義了問題的解空間後,還應將解空間很好的組織起來,使得能用回溯法方便地搜尋整個解空間。通常將解空間組織成樹或圖的形式。

  例如,對於n=3時的0-1揹包問題,可用一棵完全二叉樹表示其解空間,如圖5-1所示。

  解空間樹的第i層到第i+1層表上的標號給出了變數的值。從樹根到葉的任一路徑表示解空間中的一個元素。例如,從根節點到節點H的路徑相應於解空間中的元素(1,1,1)。

  確定瞭解空間的組織結構後,回溯法送開始節點(根節點)出發,以深度優先方式搜尋整個解空間。這個考試節點成為活結點,同時也成為當前的擴充套件節點。在當前的擴充套件結點處,搜尋向縱深方向移至一個新節點。這個新節點就成為新的活結點,併成為當前擴充套件節點,如果在當前的擴充套件節點處不能退再向縱深方向移動,則當前擴充套件節點就成為死節點。此時,應往回移動至最近的一個活結點處,並使這個活結點成為當前的擴充套件節點。回溯法以這種工作方式遞迴的在解空間中搜索,直至找到所要求的結果解空間中已無活結點為止。

  例如,對於n=3時的0-1揹包問題,考慮下面的具體例項:w=【16,15,15】,p=【45,25,25】,c=30。從圖5-1的根節點開始搜尋其解空間。開始時,根節點時唯一的活結點,也是當前的擴充套件節點。在這個擴充套件節點處,可以沿縱深方向移至節點B或者節點C。假設選擇先移至節點B。此時,節點A和節點B時活結點,節點B成為當前擴充套件節點。由於選取了w1,股災節點B處剩餘揹包容量是r=14,獲得的價值為45.從節點B處,可以移至節點D處或E。由於移至節點D至少需要w2=15的揹包容量,而現在僅有的揹包容量是r=14,故移至節點D導致不可行解。搜尋至節點E不需要揹包容量,因而是可行的。從而選擇移至節點E。此時,E成為新的擴充套件節點,節點A,B和E是活結點。在節點E處,r=14,獲取的價值為45.從節點E處,可以向縱深移至節點J或節點K。移至節點J導致不可行解,而移向節點K是可行的,於是移向節點K,它成為新的擴充套件節點。由於節點K是葉節點,故可得到一個可行解。這個解相應的價值為45。xi的取值由根節點到葉節點K的路徑唯一確定,即x=(1,0,0)。由於在節點K處已不能再向縱深擴充套件,所以節點K成為死節點。在返回到節點E處。此時在節點E處也沒有可擴充套件的節點,它也成為死節點。

  接下來又返回到節點B處。節點B同樣也成為死節點,從而節點A再次成為當前擴充套件節點。節點A還可繼續擴充套件,從而到達節點C。此時,r=30,獲取的價值為0。從節點C可移向節點F或節點G。假設移至節點F,它成為新的擴充套件節點。節點A,C,F是活結點。在節點F處,r=15,獲取的價值為25。從節點F向縱深移至節點L處,此時r=0,獲取的價值為50.由於L是葉節點,而且是迄今為止找到的獲取價值最高的可行解,因此記錄這個可行解。節點L不可擴充套件,我們返回到節點F處。按此方式繼續搜尋,可搜尋遍整個解空間。搜尋結束後找到的最好解釋相應0-1揹包問題的最優解。

#include<stdio.h>
#define max 100

int weight[max];
int value[max];
int n,max_weight,max_value;

int best_answer[max],answer[max];

void print()
{
	int i,j,k,l;
	printf("+++++++++++++%d++++++++++++\n",max_value);
	
	for(i=1;i<=n;i++)
		printf("%d ",best_answer[i]);
	printf("\n");
}

void DFS(int level,int current_weight,int current_value)
{
	if(level>=n+1)
	{
		if(current_value>max_value)
		{
			int i;
			max_value = current_value;
			for(i=1;i<=n;i++)
				best_answer[i] = answer[i];
		}
	}
	else
	{
		if(current_weight>=weight[level+1])
		{
			current_weight = current_weight - weight[level+1];
			current_value = current_value + value[level+1];
			answer[level+1] = 1;
			DFS(level+1,current_weight,current_value);
			answer[level+1] = 0;
			current_weight = current_weight + weight[level+1];
			current_value = current_value - value[level+1];
		}
		DFS(level+1,current_weight,current_value);
	}
}

void init()
{
	int i,j,k,l;
	max_value = 0;
	for(i=1;i<=n;i++)
		answer[i] = 0;
}

int main()
{
	int i,j,k,l;
	while(scanf("%d%d",&n,&max_weight)!=EOF)
	{
		for(i=1;i<=n;i++)
			scanf("%d",&weight[i]);
		for(j=1;j<=n;j++)
			scanf("%d",&value[j]);
		
		init();
		
		DFS(0,max_weight,0);
		
		print();
			
		
	}
	return 0;
	
}

/*
 3 30
 16 15 15
 45 25 25
 5 10
 2 2 6 5 4
 6 3 5 4 6 
 
 
*/