poj 2718(搜索+剪枝)C语言实现

来源:互联网 发布:看门狗2唐人街数据 编辑:程序博客网 时间:2024/06/14 10:53

题意:给你一串数字(不重复,且数字的个数在2-10之间),组成2个数字,求这2个数字差的绝对值的最小值,(其中不可以把0放在第一位比如一串数字0,2,4,5,不可以组成02,45这2个数。但可以组成20,45)

思路:递归全排列。然后前后分成2部分,计算前后2部分大小和差值,再和min比较,如果小于,更新min的值。

 剪枝(c++好像不用剪枝,直接用排列函数,暴力解就可以了,但是C不行)

  #include<stdio.h>
#include<math.h>
int p[6]={1,10,100,1000,10000,100000};
int vis[10];
int num[10],s[10];
int k,min=10000000;
void dfs(int co)
{
        int i,j,a=0,b=0,c=0;

         if(co==k)
         {

                 for(j=0;j<k/2;j++)          //第一部分数是从0到k/2     第2部分数是从k/2到k  (k代表数字的个数)   
                       a=a*10+s[j];
                 for(j=k/2;j<k;j++)
                       b=b*10+s[j];
  
                 if(abs(a-b)<min)            //更新最小值
                       {
 
                                 min=abs(a-b);
                        }
                                  return ;
  
             }
 for(i=0;i<k;i++)
 {
  
  
      if((co==0&&num[i]==0)||(co==k/2&&num[i]==0)  //当2部分数任意一部分的首位是0,就跳过。

 


             continue;
            if(co==k/2)
              {
                        c=0;
                        for(j=0;j<k/2;j++)                 //c表示第一部分数的大小
                          c=c*10+s[j];
  
                          if(abs(num[i]*p[k-k/2-1]-c)>min||num[i]==0)   //只把第2部分数字的第一位枚举出来,后面补0(按长度),
                                                          //   如果此时2数的差值还大于min,说明不管后面是什么排列,值都

                                                                    //     不可能小于min(排列的数不可能都是0)

                            continue;
    
                }
        if(!vis[i])  //递归求全排列
           {
  
               s[co]=num[i];
               vis[i]=1;
               dfs(co+1);
               vis[i]=0;
          }
        }
}
int main(void)
{

       int T,i;
       char ch;
       scanf("%d",&T);
       getchar();
       while(T--)
       {
               min=9000000;
               memset(vis,0,sizeof(vis));
               k=0;
               memset(num,0,sizeof(num));
  
                while((ch=getchar())!='\n')
                 if(ch<='9'&&ch>='0')
                    num[k++]=ch-'0';
       if(k==2)                  //只有2个数,必须特殊考虑,因为可能有0。
      printf("%d\n",abs(num[0]-num[1]));
     else
    
     {
      dfs(0);
    printf("%d\n",min);
     }
 }
}

0 0