C#使用回溯法解決背包問題實(shí)例分析
更新時間:2015年04月21日 15:51:35 作者:瘋狂一夏
這篇文章主要介紹了C#使用回溯法解決背包問題,實(shí)例分析了背包問題的描述及C#解決方法,需要的朋友可以參考下
本文實(shí)例講述了C#使用回溯法解決背包問題的方法。分享給大家供大家參考。具體如下:
背包問題描述:
給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內(nèi),我們?nèi)绾芜x擇,才能使得物品的總價格最高
實(shí)現(xiàn)代碼:
using System; using System.Collections.Generic; using System.Text; namespace BackRack { //要裝入書包的貨物節(jié)點(diǎn) class BagNode { public int mark;//貨物編號,從0開始記 public int weight;//貨物重量 public int value;//貨物價值 public BagNode(int m, int w, int v) { mark = m; weight = w; value = v; } } //根據(jù)貨物的數(shù)目,建立相應(yīng)的滿二叉樹,如:3個貨物,需要建立15個節(jié)點(diǎn)的二叉樹,共三層(根節(jié)點(diǎn)所在的層記為0) class BulidFullSubTree { public static int treeNodeNum = 0;//滿二叉樹節(jié)點(diǎn)總數(shù) public int noleafNode = 0;//滿二叉樹出去葉子節(jié)點(diǎn)外所剩余的非葉子節(jié)點(diǎn) public static TreeNode[] treeNode;//存儲滿二叉樹所有節(jié)點(diǎn)的數(shù)組 public BulidFullSubTree(int nodeNum) { treeNodeNum = Convert.ToInt32(Math.Pow(2,nodeNum+1)-1); noleafNode = Convert.ToInt32(treeNodeNum - Math.Pow(2,nodeNum)); treeNode = new TreeNode[treeNodeNum]; for (int i = 0; i < treeNodeNum; i++) { treeNode[i] = new TreeNode(i.ToString()); //對二叉樹的所有節(jié)點(diǎn)初始化 } for (int i = 0; i < noleafNode; i++) { //建立節(jié)點(diǎn)之間的關(guān)系 treeNode[i].left = treeNode[2 * i + 1]; treeNode[i].right = treeNode[2 * i + 2]; treeNode[2 * i + 1].bLeftNode = true; //如果是左孩子,則記其標(biāo)識變量為true treeNode[2 * i + 2].bLeftNode = false; } treeNode[0].level=0;//約定根節(jié)點(diǎn)的層數(shù)為0 //根據(jù)數(shù)組下標(biāo)確定節(jié)點(diǎn)的層數(shù) for (int i = 1; i <= 2; i++) { treeNode[i].level = 1; } for (int i = 3; i <= 6; i++) { treeNode[i].level = 2; } for (int i = 7; i <= 14; i++) { treeNode[i].level = 3; } } } //利用回溯法尋找最優(yōu)解的類 class DealBagProblem { public TreeNode[] treeNode = BulidFullSubTree.treeNode; //獲取建立好的二叉樹 int maxWeiht = 0;//背包最大承重量 int treeLevel =Convert.ToInt32(Math.Floor(Math.Log(BulidFullSubTree.treeNodeNum,2)))+1; //二叉樹的最大層數(shù) int []optionW=new int[100];//存儲最優(yōu)解的數(shù)組 int[] optionV = new int[100];//存儲最優(yōu)解的數(shù)組 int i = 0;//計數(shù)器,記錄相應(yīng)數(shù)組的下標(biāo) int midTw = 0;//中間變量,存儲程序回溯過程中的中間值 int midTv = 0;//中間變量,存儲程序回溯過程中的中間值 int midTw1 = 0;//中間變量,存儲程序回溯過程中的中間值 int midTv2 = 0;//中間變量,存儲程序回溯過程中的中間值 BagNode[] bagNode;//存儲貨物節(jié)點(diǎn) string[] solution=new string[3]; //程序最終所得的最優(yōu)解,分別存儲:最優(yōu)價值,總重量,路徑 // int[] bestWay=new int[100]; TraceNode[] Optiontrace=new TraceNode[100];//存儲路徑路徑 public DealBagProblem(BagNode[] bagN,TreeNode[] treeNode,int maxW) { bagNode = bagN; maxWeiht = maxW; for (int i = 0; i < Optiontrace.Length; i++) { //將路徑數(shù)組對象初始化 Optiontrace[i] = new TraceNode(); } } //核心算法,進(jìn)行回溯 //cursor:二叉樹下一個節(jié)點(diǎn)的指針;tw:當(dāng)前背包的重量;tv:當(dāng)前背包的總價值 public void BackTrace(TreeNode cursor,int tw,int tv) { if(cursor!=null)//如果當(dāng)前節(jié)點(diǎn)部位空值 { midTv = tv; midTw = tw; if (cursor.left != null && cursor.right != null) //如果當(dāng)前節(jié)點(diǎn)不是葉子節(jié)點(diǎn) { //如果當(dāng)前節(jié)點(diǎn)是根節(jié)點(diǎn),分別處理其左右子樹 if (cursor.level == 0) { BackTrace(cursor.left, tw, tv); BackTrace(cursor.right, tw, tv); } //如果當(dāng)前節(jié)點(diǎn)不是根節(jié)點(diǎn) if (cursor.level > 0) { //如果當(dāng)前節(jié)點(diǎn)是左孩子 if (cursor.bLeftNode) { //如果將當(dāng)前貨物放進(jìn)書包而不會超過背包的承重量 if (tw + bagNode[cursor.level - 1].weight <= maxWeiht) { //記錄當(dāng)前節(jié)點(diǎn)放進(jìn)書包 Optiontrace[i].mark = i; Optiontrace[i].traceStr += "1"; tw = tw + bagNode[cursor.level - 1].weight; tv=tv+bagNode[cursor.level - 1].value; if (cursor.left != null) { //如果當(dāng)前節(jié)點(diǎn)有左孩子,遞歸 BackTrace(cursor.left, tw, tv); } if (cursor.right != null) { //如果當(dāng)前節(jié)點(diǎn)有左、右孩子,遞歸 BackTrace(cursor.right, midTw, midTv); } } } //如果當(dāng)前節(jié)點(diǎn)是其父節(jié)點(diǎn)的右孩子 else { //記錄當(dāng)前節(jié)點(diǎn)下的tw,tv當(dāng)遞歸回到該節(jié)點(diǎn)時,以所記錄的值開始向當(dāng)前節(jié)點(diǎn)的右子樹遞歸 midTv2 = midTv; midTw1 = midTw; Optiontrace[i].traceStr += "0"; if (cursor.left != null) { BackTrace(cursor.left, midTw, midTv); } if (cursor.right != null) { //遞歸所傳遞的midTw1與midTv2是先前記錄下來的 BackTrace(cursor.right, midTw1, midTv2); } } } } //如果是葉子節(jié)點(diǎn),則表明已經(jīng)產(chǎn)生了一個臨時解 if (cursor.left == null && cursor.right == null) { //如果葉子節(jié)點(diǎn)是其父節(jié)點(diǎn)的左孩子 if (cursor.bLeftNode) { if (tw + bagNode[cursor.level - 1].weight <= maxWeiht) { Optiontrace[i].traceStr += "1"; tw = tw + bagNode[cursor.level - 1].weight; tv = tv + bagNode[cursor.level - 1].value; if (cursor.left != null) { BackTrace(cursor.left, tw, tv); } if (cursor.right != null) { BackTrace(cursor.right, midTw, midTv); } } } //存儲臨時優(yōu)解 optionV[i] = tv; optionW[i] = tw; i++; tv = 0; tw = 0; } } } //從所得到的臨時解數(shù)組中找到最優(yōu)解 public string[] FindBestSolution() { int bestValue=-1;//最大價值 int bestWeight = -1;//與最大價值對應(yīng)的重量 int bestMark = -1;//最優(yōu)解所對應(yīng)得數(shù)組編號(由i確定) for (int i = 0; i < optionV.Length; i++) { if (optionV[i] > bestValue) { bestValue=optionV[i]; bestMark = i; } } bestWeight=optionW[bestMark];//重量應(yīng)該與最優(yōu)解的數(shù)組下標(biāo)對應(yīng) for (int i = 0; i < Optiontrace.Length; i++) { if (Optiontrace[i].traceStr.Length == bagNode.Length&&i==bestMark) { //找到與最大價值對應(yīng)得路徑 solution[2]=Optiontrace[i].traceStr; } } solution[0] = bestWeight.ToString(); solution[1] = bestValue.ToString(); return solution; } } class Program { static void Main(string[] args) { //測試數(shù)據(jù)(貨物) //Node[] bagNode = new Node[100]; //BagNode bagNode1 = new BagNode(0, 5, 4); //BagNode bagNode2 = new BagNode(1, 3, 4); //BagNode bagNode3 = new BagNode(2, 2, 3); //測試數(shù)據(jù)(貨物) BagNode bagNode1 = new BagNode(0, 16, 45); BagNode bagNode2 = new BagNode(1, 15, 25); BagNode bagNode3 = new BagNode(2, 15, 25); BagNode[] bagNodeArr = new BagNode[] {bagNode1,bagNode2,bagNode3}; BulidFullSubTree bfs = new BulidFullSubTree(3); //第3個參數(shù)為背包的承重 DealBagProblem dbp = new DealBagProblem(bagNodeArr,BulidFullSubTree.treeNode,30); //找到最優(yōu)解并將其格式化輸出 dbp.BackTrace(BulidFullSubTree.treeNode[0],0,0); string[] reslut=dbp.FindBestSolution(); if (reslut[2] != null) { Console.WriteLine("該背包最優(yōu)情況下的貨物的重量為:{0}\n 貨物的最大總價值為:{1}", reslut[0].ToString(), reslut[1].ToString()); Console.WriteLine("\n"); Console.WriteLine("該最優(yōu)解的貨物選擇方式為:{0}", reslut[2].ToString()); char[] r = reslut[2].ToString().ToCharArray(); Console.WriteLine("被選擇的貨物有:"); for (int i = 0; i < bagNodeArr.Length; i++) { if (r[i].ToString() == "1") { Console.WriteLine("貨物編號:{0},貨物重量:{1},貨物價值:{2}", bagNodeArr[i].mark, bagNodeArr[i].weight, bagNodeArr[i].value); } } } else { Console.WriteLine("程序沒有找到最優(yōu)解,請檢查你輸入的數(shù)據(jù)是否合適!"); } } } //存儲選擇回溯路徑的節(jié)點(diǎn) public class TraceNode { public int mark;//路徑編號 public string traceStr;//所走過的路徑(1代表取,2代表舍) public TraceNode(int m,string t) { mark = m; traceStr = t; } public TraceNode() { mark = -1; traceStr = ""; } } //回溯所要依附的滿二叉樹 class TreeNode { public TreeNode left;//左孩子指針 public TreeNode right;//右孩子指針 public int level;//數(shù)的層,層數(shù)代表貨物的標(biāo)識 string symb;//節(jié)點(diǎn)的標(biāo)識,用其所在數(shù)組中的下標(biāo),如:“1”,“2” public bool bLeftNode;//當(dāng)前節(jié)點(diǎn)是否是父節(jié)點(diǎn)的左孩子 public TreeNode(TreeNode l, TreeNode r, int lev,string sb,bool ln) { left = l; right = r; level = lev; symb = sb; bLeftNode = ln; } public TreeNode(string sb) { symb = sb; } } }
希望本文所述對大家的C#程序設(shè)計有所幫助。
相關(guān)文章
extern外部方法使用C#的實(shí)現(xiàn)方法
這篇文章主要介紹了extern外部方法使用C#的實(shí)現(xiàn)方法,較為詳細(xì)的分析了外部方法使用C#的具體步驟與實(shí)現(xiàn)技巧,具有一定的參考借鑒價值,需要的朋友可以參考下2014-12-12深入淺析c#靜態(tài)多態(tài)性與動態(tài)多態(tài)性
多態(tài)就是多種形態(tài),也就是對不同對象發(fā)送同一個消息,不同對象會做出不同的響應(yīng)。這篇文章主要介紹了c#靜態(tài)多態(tài)性與動態(tài)多態(tài)性的相關(guān)知識,需要的朋友可以參考下2018-09-09C#使用IronPython庫調(diào)用Python腳本
這篇文章介紹了C#使用IronPython庫調(diào)用Python腳本的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06