Sticks

    技术2022-05-11  128

    问题描述:http://acm.pku.edu.cn/JudgeOnline/showproblem?problem_id=1011

    主要想用回溯法的思想解决它。关键是要确定搜索的顺序。要提高算法的效率还要找到合适的剪枝。

    // Sticks1.cpp : Defines the entry point for the console application.// http://acm.pku.edu.cn/JudgeOnline/showproblem?problem_id=1011// 首先将所有的小棒按从大到小的顺序排序// 搜索策略:// 每次用小棒组成原始棒,都要用到当前剩余的最长的小棒// 搜索每根原始棒的时候,组成它的每个小棒的长度由大到小排列,// 所以Search的时候有个startno,表示搜索下一个小棒的时候,从startno开始搜索#include "stdafx.h"#include <iostream>#include <algorithm>#include <functional>using namespace std;

    short len[64];bool b[64];short n,poslen,sticks;

    //stickno为要组装的第几根原始棒,startno为组装第stickno个原始棒的时候,从第startno个小棒开始查找,//leftlen表示组装第stickno个原始棒的时候,还缺多leftlen的长度bool Search(short stickno, short startno, short leftlen){ //搜索到最后一个原始棒,剩余的小棒的总长度必然等于原始棒的长度 if(stickno==sticks-1) return true;

     //搜索第stickno个原始棒,如果第stickno个小棒还没使用,表明 //第stickno个小棒不能参与组成原始棒,则整个搜索失败 if( stickno>0 && !b[stickno-1] ) return false;

     for(int i=startno; i<n; i++) {  if(!b[i])  {   //如果有连续的几根小棒长度相等,且前一个小棒不被使用,则当前小棒也不能使用,避免重复搜索   if( (i>0)&&(!b[i-1]) && (len[i-1]==len[i])) continue;

       //正好组成一个原始棒   if(len[i]==leftlen)   {    b[i] = true;    //搜索下一个原始棒,如果成功则返回true,如果失败,则回溯    if (Search(stickno+1,0,poslen)) return true;    b[i] = false;   }   else if(len[i]<leftlen)   {    int j = n-1;    while(b[j])     j--;        if(len[i]+len[j]<=leftlen)    {     b[i] = true;     if(Search(stickno,i+1,leftlen-len[i])) return true;//此处的第二个参数设为i+1非常关键,提高了搜索速度     b[i] = false;    }   }  } }

     return false;}

    void main(){ short i,maxlen,totallen; cin>>n; while(n) {  maxlen = totallen = 0;

      for(i=0; i<n; i++)  {   cin>>len[i];   if(len[i]>50)    len[i]=0;   totallen += len[i];   if(len[i]>maxlen)    maxlen = len[i];  }

      //对每小段的大小按从大到小的顺序排序  sort(&len[0],&len[n],greater<int>());  //清除长度为0的棒  i=0;  while((i<n)&&(len[i]>0)) i++;   n = i;

      for(poslen=maxlen; poslen<totallen; poslen++)  {   //棒的个数不为整数则改变poslen的大小再试   if(totallen%poslen) continue;

       //将所有小段设为未选择   memset(b,0,n*sizeof(bool));

       //为每根长度为poslen的stick找到各个小段,这些小段的和为poslen   sticks = totallen / poslen;   if(Search(0,0,poslen))    break;  }  cout<<poslen<<endl;

      cin>>n; }}


    最新回复(0)