C语言标准库函数 qsort详解

第一篇


qsort(基本快速排序的方法,每次把数组分成两部分和中间的一个划分值,而对于有多个重复值的数组来说,基本快速排序的效率较低,且不稳定)。集成在C语言库函数里面的的qsort函数,使用 路划分的方法解决排序这个问题。所谓三路划分,是指把数组划分成小于划分值,等于划分值和大于划分值的三个部分。

 

具体介绍:-^^

voidqsort( void *base, size_t num, size_t width, int (__cdecl *compare )

intcompare (const void *elem1, const void *elem2 ) );

 

qsort(即,quicksort)主要根据你给的比较条件给一个快速排序,主要是通过指针移动实现排序功能。排序之后的结果仍然放在原来数组中。

参数意义如下:

第一个参数 base 需要排序的目标数组名(或者也可以理解成开始排序的地址,因为可以写&s[i]这样的表达式)

第二个参数 num 参与排序的目标数组元素个数

第三个参数 width 是单个元素的大小(或者目标数组中每一个元素长度),推荐使用sizeof(s[0])这样的表达式

第四个参数 compare 就是让很多人觉得非常困惑的比较函数啦。

 

我们来简单讨论compare这个比较函数(写成compare是我的个人喜好,你可以随便写成什么,比如 cmp 什么的,在后面我会一直用cmp做解释)。

 

典型的compare的定义是int compare(const void *a,constvoid *b);

返回值必须是int,两个参数的类型必须都是const void *,那个a,b是随便写的,个人喜好。假设是对int排序的话,如果是升序,那么就是如果ab大返回一个正值,小则负值,相等返回0,其他的依次类推,后面有例子来说明对不同的类型如何进行排序。

 

 

qsort的使用方法:

一、对int类型数组排序

intnum[100];

intcmp ( const void *a , const void *b )

{

  return *(int *)a - *(int *)b;  //升序排序

//return*(int *)b - *(int *)a; //降序排序

/*可见:参数列表是两个空指针,现在他要去指向你的数组元素。所以转型为你当前的类型,然后取值。

        升序排列时,若第一个参数指针指向的大于第二个参数指针指向的,则返回正;若第一个参数指针指向的等于第二个参数指针指向的,则返回零;若第一个参数指针指向的小于第二个参数指针指向的,则返回负。

        降序排列时,则刚好相反。

*/

}

qsort(s,n,sizeof(s[0]),cmp);

 

示例完整函数(已在 VC6.0上运行通过):

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

ints[10000],n,i;

intcmp(const void *a,const void *b)

{

return(*(int*)b-*(int *)a);  //实现的是升序排序

}

intmain()

{

//输入想要输入的数的个数

scanf("%d",&n);

for(i=0;i<n;i++)

scanf("%d",&s[i]);

qsort(s,n,sizeof(s[0]),cmp);

for(i=0;i<n;i++)

printf("%d",s[i]);

return(0);

}

 

二、对char类型数组排序(同int类型)

charword[100];

intcmp( const void *a , const void *b )

{

//注意,网上很多版本是 “ return *(char *)a - *(int *)b; ”

//因为编辑者的不用心,盲目copy,以讹传讹,传的一直是错的 *(int *)b

//应该是return*(char *)a - *(char *)b;

return*(char *)a - *(char *)b;

}

qsort(word,100,sizeof(word[0]),cmp);

//附,可能getchar();  会派上用场

 

三、对double类型数组排序(特别要注意)

doublein[100];

intcmp( const void *a , const void *b )

{

return*(double *)a > *(double *)b ? 1 : -1;

//返回值的问题,显然cmp返回的是一个整型,所以避免double返回小数而被丢失,用一个判断返回值。

}

qsort(in,100,sizeof(in[0]),cmp);

 //附:排序结果的输出,一般建议用 “ %g ” 格式

/*在这里多嘴一句,"%g"格式输出 虽然书上是说系统会自动选择 " %f " 格式  " %e " 格式 中长度较短的格式,并去掉无意义的0,但实际上系统如果选择了" %e ",系统会输出比 “ %e " 格式更省一位的格式输出。(此结论,来自VC6.0的实际操作)*/

 

四、对结构体一级排序

structIn

{

doubledata;

intother;

}s[100]

 

//按照data的值从小到大将结构体排序,关于结构体内的排序关键数据data的类型可以很多种,参考上面的例子写

 

intcmp( const void *a ,const void *b)

{

return(*(In *)a).data > (*(In *)b).data ? 1 : -1;

//注意,这条语句在VC6.0环境下运行可能会出错,但是并不是语句错了,而是你要先 Build ,或者全部重建。总之语句是对的。

//或者你可以将这上面1条语句改成下面这3条语句

//structIn *aa = (In *)a;

//structIn *bb = (In *)b;

//returnaa->data > bb->data ? 1 : -1;

}

qsort(s,100,sizeof(s[0]),cmp);

 

五、对结构体二级排序

structIn

{

intx;   //你可以比喻成:失败次数

inty;   //你可以比喻成:成功次数

}s[100];

 

//按照x从小到大排序,当x相等时按照y从大到小排序。 你可以想象成:失败是主要因素的一个问题,先比较 失败次数少,失败次数相同 再看 成功次数多。

 

intcmp( const void *a , const void *b )

{

structIn *c = (In *)a;

structIn *d = (In *)b;

if(c->x!= d->x) return c->x - d->x;

elsereturn d->y - c->y;

}

qsort(s,100,sizeof(s[0]),cmp);

 

六、对字符串进行排序

structIn

{

intdata;

charstr[100];

}s[100];

//按照结构体中字符串str的字典顺序排序

intcmp ( const void *a , const void *b )

{

returnstrcmp( (*(In *)a)->str , (*(In *)b)->str );

}

qsort(s,100,sizeof(s[0]),cmp);

 

注意!qsort 中的 cmp 得自己写

 

 

再说说   sort (常用于  C++

sort使用时得注明:using namespace std;  或直接打 std::sort()  还得加上  #include <algorithm> 头文件

 

例:

#include<iostream>

#include<algorithm>

usingnamespace std;

 

intmain()

{

     inta[20];

   for(int i=0;i<20;++i)

              cin>>a[i];

 

     sort(a,a+20);             //范围,很明显这里是a+20 注意,这是必要的,如果是a+19

       for(i=0;i<20;i++)        //最后一个值a[19]就不会参与排序。

              cout<<a[i]<<endl;

     return0;

}

 

std::sort是一个改进版的qsort. std::sort函数优于qsort的一些特点:对大数组采取9项取样,更完全的三路划分算法,更细致的对不同数组大小采用不同方法排序。

 

 

 

最后,我们来说说sortqsort的区别:

 

sortqsort的升级版,如果能用sort尽量用sort,使用也比较简单,不像qsort还得自己去写 cmp 函数,只要注明 使用的库函数就可以使用,参数只有两个(如果是普通用法)头指针和尾指针;

 

默认sort排序后是升序,如果想让他降序排列,可以使用自己编的cmp函数

#include<iostream>

#include<algorithm>

usingnamespace std;

intcmp(int a,int b)

{

  if(a<b)

  return 1; //升序排列,如果改为 a >b,则为降序,要注意sort()cmp()的返值只有10,不像qsort中存在-1!!!!

  else

  return 0;

}

 

intmain(){

       int i;

 int a[20];

 for(int i=0;i<5;++i)

  cin>>a[i];

sort(a,a+5,cmp);          //范围,很明显这里是a+5 注意,这是必要的,如果是a+4最后一个值a[4]就不会参与排序。

for(i=0;i<5;i++)      

cout<<a[i]<<endl;

       system("pause");

 return 0;

}

 

对二维数组的排序:

#include<iostream>

#include<algorithm>

#include<ctime>

usingnamespace std;

 

boolcmp(int *p,int *q)

{

       if(p[0]==q[0])

       {

           if(p[1]==q[1])

           {

               returnp[2]<q[2];

           }

           elsereturn p[1]<q[1];

       }

       else return p[0]<q[0];

}

intmain()

{

       srand(time(0));

       int i;

       int **a=new int*[1000];

       for(i=0;i<1000;++i)

       {

           a[i]=newint[3];

           a[i][0]=rand()%1000;

           a[i][1]=rand()%1000;

           a[i][2]=rand()%1000;

           //printf("%d\t%d\t%d\n",a[i][0],a[i][1],a[i][2]);

       }

       sort(a,a+1000,cmp);

       /*cout<<"Aftersort"<<endl;

       for(i=0;i<1000;++i)

       {

           printf("%d\t%d\t%d\n",a[i][0],a[i][1],a[i][2]);

       }*/

       return 0;

}

 

 



第二篇


C语言标准库函数 qsort详解

       qsort包含在<stdlib.h>头文件中,此函数根据你给的比较条件进行快速排序,通过指针移动实现排序。排序之后的结果仍然放在原数组中。使用qsort函数必须自己写一个比较函数。

 

函数原型:

void qsort ( void * base, size_tnum, size_t size, int ( * comparator ) ( const void *, const void * ) );

 

指向任意数据类型的指针都可以转换为void*类型

用法以及参数说明:

       Sortsthe num elements of the array pointed by base, each element size bytes long,using the comparator function to determine the order.

       Thesorting algorithm used by this function compares pairs of values by calling thespecified comparator function with two pointers to elements of the array.

       Thefunction does not return any value, but modifies the content of the arraypointed by base reordering its elements to the newly sorted order.

       basePointer to the first element of the array to be sorted.(数组起始地址)

       numNumber of elements in the array pointed by base.(数组元素个数)

       sizeSize in bytes of each element in the array.(每一个元素的大小)

       comparatorFunction that compares two elements.(函数指针,指向比较函数)

1、The function must accept two parameters that are pointers to elements,type-casted as void*. These parameters should be cast back to some data typeand be compared.

2、The return value of this function should represent whether elem1 isconsidered less than, equal to, or greater than elem2 by returning,respectively, a negative value, zero or a positive value.

Return Value none (无返回值)

 

 

       给你们的C++帮助文档上面的语法及定义是:

语法:

#include <stdlib.h>

void qsort( void *buf, size_t num, size_t size, int (*compare)(const void *, const void *) );

功能:buf 指向的数据(包含num 项,每项的大小为size)进行快速排序。如果函数compare 的第一个参数小于第二个参数,返回负值;如果等于返回零值;如果大于返回正值。函数对buf 指向的数据按升序排序。

 

关键比较函数

一、对int类型数组排序

int num[100];

int cmp ( const void *a , const void *b )
{
      return *(int *)a - *(int *)b;
}

 

 

qsort对int类型的数组排序

#include<iostream>

using namespace std;

 

int num[100];

int cmp(const void* a,const void* b)

{

    return*(int*)a - *(int*)b;

}

int main()

{

    intn,i;

    cout<<"请输入数组大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i];

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i]<<endl;

       else

           cout<<num[i]<<" ";

    }

    return0;

}

 

 

 

 

 

二、对char类型数组排序(同int类型)

char word[100];

int cmp( const void *a , const void *b )
{
      return *(char *)a - *(char *)b;
}

qsort(word,100,sizeof(word[0]),cmp);

 

注:按ASCII码排序,类似int

qsort对char类型的数组排序

#include<iostream>

using namespace std;

 

char num[100];

int cmp(const void* a,const void* b)

{

    return*(char*)a - *(char*)b;

}

int main()

{

    intn,i;

    cout<<"请输入数组大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i];

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i]<<endl;

       else

           cout<<num[i]<<" ";

    }

    return0;}

 

 

 

 

三、对double类型数组排序

double in[100];

int cmp( const void *a , const void *b )
{
      return *(double *)a > *(double*)b ? 1 : -1;
}

qsort(in,100,sizeof(in[0]),cmp);

 

 

 

qsort对double类型的数组排序

#include<iostream>

using namespace std;

 

double num[100];

int cmp(const void* a,const void* b)

{

    return*(double*)a - *(double*)b;

}

int main()

{

    intn,i;

    cout<<"请输入数组大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i];

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i]<<endl;

       else

           cout<<num[i]<<" ";

    }

       return 0;}

 

 

 

四、对结构体一级排序

struct Sample

{

    doubledata;

    intother;

}s[100];

 

//按照data的值从小到大将结构体排序

int cmp( const void *a ,const void *b)

{

    return(*(Sample *)a).data > (*(Sample *)b).data ? 1 : -1;

}

 

qsort(s,100,sizeof(s[0]),cmp);

 

程序

qsort对结构类型的数组一级排序

#include<iostream>

using namespace std;

 

struct Sample

{

    intdata;

    charother;

};

 

Sample num[100];///结构数组

 

int cmp(const void* a,const void* b)

{

    return((Sample*)a)->data - ((Sample*)b)->data;

    //return(*(Sample*)a).data - (*(Sample*)b).data;也行的,一个是解引用,一个是直接指针指向

}

int main()

{

    intn,i;

    cout<<"请输入数组大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i].data>>num[i].other;

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i].data<<" "<<num[i].other<<endl;

       else

           cout<<num[i].data<<" "<<num[i].other<<" ";

    }

    return0;

}

五、对结构体二级排序

 

struct Sample

{

int x;

int y;

}s[100];

 

//按照x从小到大排序,当x相等时按照y从大到小排序

 

int cmp( const void *a , const void *b )

{

    structSample *c = (Sample *)a;

    structSample *d = (Sample *)b;

    if(c->x!= d->x)

       returnc->x - d->x;

    else

       return d->y - c->y;

}

 

qsort(s,100,sizeof(s[0]),cmp);

 

 

 

qsort对结构类型的数组二级排序

#include<iostream>

using namespace std;

 

struct Sample

{

    intdata;

    charother;

};

Sample num[100];///结构数组

int cmp(const void* a,const void* b)

{

    Sample *c = (Sample*)a;

    Sample *d = (Sample*)b;

    if(c->data== d->data)

       returnc->other - d->other;如果结构体中的data相等则执行第二级排序

    else

       returnc->data - d->data;

}

int main()

{

    intn,i;

    cout<<"请输入数组大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i].data>>num[i].other;

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i].data<<" "<<num[i].other<<endl;

       else

           cout<<num[i].data<<" "<<num[i].other<<" ";

    }

    return0;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

六、对字符串进行排序

struct Sample

{

    intdata;

    charstr[100];

}s[100];

 

//按照结构体中字符串str的字典顺序排序

int cmp ( const void *a , const void *b )

{

    returnstrcmp( (*(Sample *)a)->str , (*(Sample *)b)->str );

}

qsort(s,100,sizeof(s[0]),cmp);

对字符串进行排序

#include<iostream>

using namespace std;

struct Sample

{

    charch[100];

};

Sample num[100];///结构数组

int cmp(const void* a,const void* b)

{

    returnstrcmp( ((Sample*)a)->ch,((Sample*)b)->ch );

}

int main()

{

    intn,i;

    cout<<"请输入数组大小:"<<endl;

    cin>>n;

    for(i=0;i<n;i++)///初始化

       cin>>num[i].ch;

    qsort(num,n,sizeof(num[0]),cmp);

    for(i=0;i<n;i++)

    {

       if(i==n-1)

           cout<<num[i].ch<<endl;

       else

           cout<<num[i].ch<<" ";

    }

    return0;

}

 

附加一个完整点的代码,对字符串二维数组排序:

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

char s[2001][1001];

 

int cmp(const void *a, const void *b){

    returnstrcmp((char *)a,(char*)b);

}

 

int main(){

    inti,n;

    scanf("%d",&n);

    getchar();

    for(i=0;i<n;i++)

           gets(s[i]);

    qsort(s,n,1001*sizeof(char),cmp);

    for(i=0;i<n;i++)

           puts(s[i]);

    return0;

}

Sort()函数类似,不再一步一步举例,可以自学了

2、sort()

sort 对给定区间所有元素进行排序

stable_sort 对给定区间所有元素进行稳定排序

partial_sort 对给定区间所有元素部分排序

partial_sort_copy 对给定区间复制并排序

nth_element 找出给定区间的某个位置对应的元素

is_sorted 判断一个区间是否已经排好序

partition 使得符合某个条件的元素放在前面

stable_partition 相对稳定的使得符合某个条件的元素放在前面

 

 

 

 

 

 

 

 

语法描述为:

1sort(begin,end),表示一个范围,例如:

int _tmain(int argc, _TCHAR* argv[])

{

 int a[20]={2,4,1,23,5,76,0,43,24,65},i;

 for(i=0;i<20;i++)

  cout<<a[i]<<endl;

 sort(a,a+20);

 for(i=0;i<20;i++)

 cout<<a[i]<<endl;

 return 0;

}

输出结果将是把数组a按升序排序,说到这里可能就有人会问怎么样用它降序排列呢?这就是下一个讨论的内容。

 

(2)sort(begin,end,compare)

一种是自己编写一个比较函数来实现,接着调用三个参数的sort:sort(begin,end,compare)就成了。对于list容器,这个方法也适用,把compare作为sort的参数就可以了,即:sort(compare)。

1)自己编写compare函数:

bool compare(int a,int b)

{

 return a<b; //升序排列,如果改为return a>b,则为降序

}

int _tmain(int argc, _TCHAR* argv[])

{

  inta[20]={2,4,1,23,5,76,0,43,24,65},i;

 for(i=0;i<20;i++)

 cout<<a[i]<<endl;

  sort(a,a+20,compare);

 for(i=0;i<20;i++)

 cout<<a[i]<<endl;

 return 0;

}

2)更进一步,让这种操作更加能适应变化。也就是说,能给比较函数一个参数,用来指示是按升序还是按降序排,这回轮到函数对象出场了。

为了描述方便,我先定义一个枚举类型EnumComp用来表示升序和降序。很简单:

enum Enumcomp{ASC,DESC};

然后开始用一个类来描述这个函数对象。它会根据它的参数来决定是采用“<”还是“>”。

class compare

{

 private:

 Enumcomp comp;

 public:

 compare(Enumcomp c):comp(c) {};

 bool operator () (int num1,int num2)

  {

 switch(comp)

  {

 case ASC:

 return num1<num2;

  case DESC:

  return num1>num2;

  }

  }

};

 

接下来使用 sort(begin,end,compare(ASC))实现升序,sort(begin,end,compare(DESC))实现降序

主函数为:

int main()

{

  inta[20]={2,4,1,23,5,76,0,43,24,65},i;

 for(i=0;i<20;i++)

 cout<<a[i]<<endl;

 sort(a,a+20,compare(DESC));

 for(i=0;i<20;i++)

 cout<<a[i]<<endl;

 return 0;

}

3)其实对于这么简单的任务(类型支持“<”、“>”等比较运算符),完全没必要自己写一个类出来。标准库里已经有现成的了,就在functional里,include进来就行了。functional提供了一堆基于模板的比较函数对象。它们是(看名字就知道意思了):equal_to<Type>、not_equal_to<Type>、greater<Type>、greater_equal<Type>、less<Type>、less_equal<Type>。对于这个问题来说,greater和less就足够了,直接拿过来用:

 

升序:sort(begin,end,less<data-type>());

降序:sort(begin,end,greater<data-type>()).

int _tmain(int argc, _TCHAR* argv[])

{

  int a[20]={2,4,1,23,5,76,0,43,24,65},i;

  for(i=0;i<20;i++)

  cout<<a[i]<<endl;

 sort(a,a+20,greater<int>());

 for(i=0;i<20;i++)

 cout<<a[i]<<endl;

 return 0;

}

4)既然有迭代器,如果是string 就可以使用反向迭代器来完成逆序排列,程序如下:

int main()

{

 string str("cvicses");

 string s(str.rbegin(),str.rend());

 cout << s <<endl;

 return 0;

}

----------------------------------------------------------------------------------------------------------------

POJ1011

Description

 

George took sticks of the same length andcut them randomly until all parts became at most 50 units long. Now he wants toreturn sticks to the original state, but he forgot how many sticks he hadoriginally and how long they were originally. Please help him and design aprogram which computes the smallest possible original length of those sticks.All lengths expressed in units are integers greater than zero.

Input

 

The input contains blocks of 2 lines. Thefirst line contains the number of sticks parts after cutting, there are at most64 sticks. The second line contains the lengths of those parts separated by thespace. The last line of the file contains zero.

Output

 

The output should contains the smallestpossible length of original sticks, one per line.

Sample Input

 

9

5 2 1 5 2 1 5 2 1

4

1 2 3 4

0

 

Sample Output

 

6

5

【原题链接】

      http://acm.pku.edu.cn/JudgeOnline/problem?id=1011

 

【题意描述】

      给出N根小木棒(以下称小棒)的长度Li,已知这N根小木棒原本由若干根长度相同的长木棒(以下称原棒)分解而来。要求出原棒的最小可能长度。

数据范围】

      木棒数N<=64

      任意小棒长度Li<=50

 

【题目类型】

      这题在网络上被称为经典的深搜题,其中用到的搜索方法和剪枝技巧十分经典。就我做过这题之后的感受来看,的确如此。其中的许多技巧效果非常显著而且在其它搜索题中也经常用到。另外建议大家在做搜索题的时候加上时间测试,以便在调程序的时候观察和比较各项剪枝带来的效率提升。

 

【解题思路】

      由小到大枚举所有可能的原棒长度,通过深度优先搜索尝试小棒能否组合成原棒,一旦检验成功则算法结束,当前原棒长度即为最小可能原棒长度。

      枚举过程如下,设小棒的总长为SUM,最长小棒长度为MAX,从MAX开始由小到大枚举原棒长度LEN,使得LEN能被SUM整除。然后进行搜索,尝试用所有小棒拼出SUM/LEN根的原棒。

搜索过程如下,首先用一数组标USED[]记某一小棒在当前状态下是否已经被用于组合原棒,另有有两个主要参数表示搜索时的状态,CPL表示已经组合好的原棒数,RES表示当前正在组合的原棒(以下称当前原棒)已组合出的长度。在每一种状态下,尝试所有可能拼接在当前原棒上的未使用的小棒,即将满足USED=FALSE且RES+Li<=LEN的小棒接入当前原棒,传递RES的参数RES+Li,若RES+Li=LEN,传递CPL的参数CPL+1,否则,传递CPL,同时令USED=TRUE,然后进行递归,进入下一层搜索。退出下层递归后,将USED重新赋为FALSE。当CPL=SUM/LEN时,返回TRUE,表示搜索成功,一旦下一层递归返回TRUE,当前递归也返回TRUE,不断返回,直到跳出函数调用,表示当前原棒长度为可行解,且为最小,输出。

本题的难点在于搜索的方法和剪枝的技巧。本题中用到的主要技巧有:

      1. 搜索顺序。首先依据小棒长度进行由大到小的排序,在每一层搜索时首先将长度大的小棒填入当前原棒中。因为当相对长的小棒占据了原棒的大部分空间后能大大减小可行的搜索状态。

      2. 利用排序剪枝。在组合同一支原棒的时候,由于检验小棒是否可用的顺序也是由大到小的,因此在检验到一支小棒可用时,如果当前棒还合填满,可能填入当前棒的小棒的长度也不会比现在填入的这支小棒长。因此,增加一个递归参数NEXT表示可能用于组合当前棒的第一支小棒的数组下标。参数传递时,若当前正好拼成一支原棒,NEXT还原回1,否则将NEXT+1传递给下一层递归。

      3. 不进行重复搜索。即在某一状态,若将某一长度的小棒填入当前原棒进行搜索无法最终拼出所有原棒,则对于当前状态,相同长度的小棒也无法填入当前原棒而得到最终解。因此,在记录小棒长度的数组L中增加一指针用于指向下一个与之长度不同的小棒的数组下标,则搜索时,若某一长度小棒不成功,直接尝试下一个与之长度不同的小棒。

      4. 首次只尝试最长的小棒。在第一次组合拼接某一根原棒时,首先放入的是当前最长的小棒,并且,如果当前状态可以完成组合,则该小棒必定要放入之后的某一根原棒中,即假设它放在当前原棒中,若放入后搜索失败,则当前状态必定不可能成功,需要回溯。因此,在RES=0时,若第一次搜索失败,则不断续当前状态的其它搜索。

      5.如果当前最长的一支可用小棒L'0恰能填满当前正在组合的一支原棒,则如果此次尝试失败,在当前状态下不再做其它尝试,返回上一层递归。因为若当前状态还有可能成功,则当前原棒的剩余长度必定能由另几支更短的小棒L'1、L'2……L'n组合成,且L'0必定出现在之后组合的某支原棒之中,则可以将其中的L'0替换为L'1、L'2……L'n,而将L'0移加当前原棒中,则两种状态等价,因此同样必定失败。因此,在RES+Li=LEN时,若搜索失败,则同样不断续当前状态的其它搜索。

6. 判断所剩可用小棒是否足够拼接当前原棒。累加所有小于当前已经尝试的小棒的长度且未使用的小棒,判断是否足够拼接出当前原棒,若不能,则不继续当前搜索。该剪枝效果不很明显,且计算位置放置不佳可能反而降低率效。

 

百度上找到的1011题的答案,我觉得用它来说明sort()函数最具有代表性

 

#include <iostream>

#include <algorithm>

#include <cstdio>

#include <functional>

using namespace std;

int stick[100], n;

bool used[100];

 

//unused:没有使用的棍子的数目

//left:剩下的长度

//len:当前认为的计算的长度

bool dfs(int unused, int left, int len)

{

       // 所有的棍子已经用了,且没有剩余的长度,符合搜索条件

       if (unused == 0 && left == 0)

       return true;

       int i;

       //没有剩下的.则新开一条棍子

       if (left == 0)

       left = len;

       //寻找没有使用过的棍子

       for (i=0; i<n; ++i)

       {

                //找到没有用过的,而且长度比left值要小(能够填进去)

                if (!used &&stick<=left)

                {

                        //使用当前棍子

                        used = true;

                        //若在当前情况下能够扩展出正确答案,则返回

                        if (dfs(unused-1,left-stick, len))

                                //成功搜索,返回

                                return true;

                       //否则不使用当前的棍子

                        used = false;

                        //若使用stick不能扩展出正确结果,那么如果stick与left等长,则证明len不可能是正确答案

                        //若left与len等长,就是没有办法扩展

                        if (stick == left ||left == len)

                               break;

                }

       }

       //经过一轮搜索仍得不到正确答案,则返回false

       return false;

int main()

{

       int i, sum;

       while (scanf("%d", &n) != EOF && n)

        {

                sum = 0;

                for (i=0; i<n; ++i)

                {

                        scanf("%d",&stick);

                        used = false;

                        sum += stick;

                }

                //先进行从大到小排序

                sort(stick, stick+n,greater<int>());

                //根据题目条件,从小向大寻找

                for (i=stick[0]; i<=sum;++i)

                {

                        //棍子总长被i整除才进行搜索,否则没用

                        if (sum % i == 0)

                        {

                                if (dfs(n, 0,i))

                                {

                                       printf("%d\n", i);

                                        break;

                                }

                        }

                }

       }

       return 0;

}

 

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值