zoukankan      html  css  js  c++  java
  • 经典剪枝算法的例题——Sticks详细注释版

    这题听说是道十分经典的剪枝算的题目,不要问我剪枝是什么,我也不知道鄙视,反正我只知道用到了深度搜索

    我参考了好多资料才悟懂,然后我发现网上的那些大神原理讲的很明白,但代码没多少注释,看的很懵X,于是我抄起VS写了个详细注释版,真的很详细,史上最详细,全宇宙最详细,就这么自信,不信你看,看不懂你咬我。

    /*--------------------------------------------
    *     剪枝算法经典例题Sticks详细注释版
    *---------------------------------------------*/
    
    #include <iostream>
    
    using namespace std;
    
    //某根木棍被使用过就设置标志位为1,没使用过则设置标志位为0
    #define USED 1
    #define UNUSED 0
    #define MAXSIZE 64
    
    //定义木棍结构体
    typedef struct Stick
    {
    	int length;//每根木棍的长度
    	int mark;//标志位,记录是否被使用过
    }Sticks[MAXSIZE];
    
    //虽然程序中使用全局变量是不好的习惯,但做题who care
    int n;//未拼接时的总木棒数
    int g;//拼接好后的木棒数
    int len;//满足要求的拼接后的木棒的长度
    Sticks sticks;//定义一个木棒集合,记录未拼接时各木棒的信息
    
    //定义一个冒泡排序算法,从大到小排序
    void BubbleSort(Sticks *a,int num)
    {
    	int i,j;
    	int temp;//交换时用的中间变量
    	for (i = 0;i<num-1;i++)
    	{
    		for (j = 0;j<num-1;j++)
    		{
    			if ((*a)[j].length<(*a)[j+1].length)
    			{
    				//交换
    				temp = (*a)[j].length;
    				(*a)[j].length = (*a)[j+1].length;
    				(*a)[j+1].length = temp;
    			}
    		}
    	}
    }
    
    /*剪枝函数,深度搜索
    *总共三个参数,nowLen表示现在拼接成的木棒的长度,
    *nowGet表示现在拼接成的木棒的总数,此值若等于之前的g则说明找到符合要求的木棒长,
    *cnt表示拼接过程中查找剩下符合要求的木棒从哪个下标开始查找,当cnt大于n时说明没有符合要求的拼接方法
    *该函数返回1代表找到了,0代表没有找到符合要求的*/
    int DFS(int nowLen,int nowGet,int cnt)
    {
    	if (cnt>=n) return 0;//找的下标都超了,肯定不满足
    	if (nowGet == g) return 1;//如果这个长度下获取的总个数与g相等说明符合条件
    	int i;
    
    	//开始遍历查找
    	for (i = cnt;i<n;i++)
    	{
    		if (sticks[i].mark==UNUSED)
    		{
    			//当找到的一组木棒恰好能拼接成需要的长度时
    			if (nowLen+sticks[i].length == len)
    			{
    				sticks[i].mark = USED;//设置这个木棒已使用过
    				//这组满足,开始下一组寻找
    				if (DFS(0,nowGet+1,nowGet)==1)
    				{
    					//递归,直到最后每一组都满足需要的长度时说明这个长度可行
    					return 1;
    				}
    				sticks[i].mark = UNUSED;//解除使用
    				return 0;
    			}
    			//当找到的一组木棒还小于拼接成需要的长度时
    			else if(nowLen+sticks[i].length < len)
    			{
    				sticks[i].mark = USED;//设置这个木棒已使用过
    				if(DFS(nowLen+sticks[i].length,nowGet,i+1)==1)
    				{
    					//同样递归,这里说明一下i+1,这个意思是从i+1下标开始寻找要使这组木棒满足要求的木棒
    					return 1;
    				}
    				sticks[i].mark = UNUSED;//解除使用
    				//下面这句表示如果当前搜索时,前边的长度为0,而第一根没有成功的使用,
    				//说明第一根始终要被废弃,所以这种组合必定不会成功
    				//此处的剪枝必须有,因为这里的剪枝会节省很多的无用搜索,
    				//缺少这一句超时
    				if (nowLen == 0) return 0;
    				//下面这句是指如果有一根木棒加上去已经知道不满足要求了,则与它相同长度的木棒都可以跳过
    				for ( ;sticks[i].length==sticks[i+1].length&&i+1<n;i++);
    			}
    		}
    	
    	}
    
    	return 0;
    }
    
    int main()
    {
    	int i;
    	int sum;//木棒的总长
    
    	//用户输入每组的木棒数
    	while(cin>>n,n)
    	{
    		//木棒一开始都初始化为未使用过的
    		for (i = 0;i<MAXSIZE;i++)
    		{
    			sticks[i].mark = UNUSED;
    		}
    		sum = 0;
    		for (i = 0;i<n;i++)
    		{
    			cin>>sticks[i].length;
    			sum+=sticks[i].length;
    		}
    		
    		//从大到小排序
    		BubbleSort(&sticks,n);
    		for (len = sticks[0].length;len<=sum;len++)
    		{
    			if (sum%len!=0) continue;//最后选的木棒长度一定是能被总木棒长整除的
    
    			g = sum/len;//拼接的后的木棒数
    			//剪枝,满足要求退出循环
    			if(DFS(0,0,0))
    			{
    				break;
    			}
    		}
    		//输出满足要求的木棒长
    		cout << len<<endl;
    	}
    
    	return 0;
    }

  • 相关阅读:
    【刷题】BZOJ 1036 [ZJOI2008]树的统计Count
    【刷题】BZOJ 1180 [CROATIAN2009]OTOCI
    【刷题】BZOJ 1453 [Wc]Dface双面棋盘
    【刷题】BZOJ 4025 二分图
    【模考】2018.04.08 Connection
    【模考】2018.04.08 Travel
    【刷题】BZOJ 4825 [Hnoi2017]单旋
    【刷题】洛谷 P3613 睡觉困难综合征
    【刷题】BZOJ 3668 [Noi2014]起床困难综合症
    CSS3_边框 border 详解_一个 div 的阴阳图
  • 原文地址:https://www.cnblogs.com/sj2050/p/13413723.html
Copyright © 2011-2022 走看看