码迷,mamicode.com
首页 > 其他好文 > 详细

(暴力+深搜)POJ - 2718 Smallest Difference

时间:2016-08-16 01:55:23      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:

原题链接:

http://poj.org/problem?id=2718


题意:

给你几个数字,可以分成两个子集,然后分别按一定顺序排列组成一个数,求出这两只值差的绝对值的最小值。


分析:

反正也是刷着玩,果断先交一波全排列枚举的代码,果断TLE,然后开始想正解。

稍微想想,既然要差最小,肯定是两个数各一半。所以只要深搜出所有n/2(n为给定数字的个数)的组合,另外个n-n/2个数就有了。

但是枚举出来后的操作又想了很久,想过很多算法,都不怎么满意,最终用二分解决。

先把n/2和n-n/2全排列,算了出所有可能组成的整数,然后进行二分,分别和最近的作差比较,需要注意特殊处理。

坑点:忘记了单个0需要特殊考虑,导致WA了好几发,马蛋。

最坏时间复杂度(n==10)C(5,10)×(5!×5)×2==302400。跑了32ms。

算是很快了,不过肯定有比我更快的,膜拜各路大神。


代码:

 

  1 #include <iostream>
  2 #include <sstream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <vector>
  6 #include <set>
  7 #include <map>
  8 #include <algorithm>
  9 #include <string>
 10 #include <queue>
 11 #include <cmath>
 12 #include <stack>
 13 #include <cctype>
 14 #include <list>
 15 
 16 #define ll long long
 17 #define ull unsigned long long
 18 #define VNAME(name) (#name)
 19 #define debug(a) cout<<VNAME(a)<<" = "<<(a)<<endl;
 20 
 21 
 22 
 23 using namespace std;
 24 
 25 const int maxn = 110;
 26 const int inf = 1 << 30;
 27 
 28 string str;
 29 int num[maxn];
 30 int a[maxn],b[maxn];//保存在深搜中组合出的数列
 31 bool vis[maxn];//回溯标记
 32 int n;
 33 int ans;
 34 
 35 //全排列算出每个组成的整数
 36 int make_permutation(int x,int *org,int *ne,int *num){
 37     for(int i=0;i<x;i++){
 38         ne[i]=org[i];
 39     }
 40     sort(ne,ne+x);
 41     int nn=0;
 42     do{
 43         if(ne[0]==0)continue;//0前导忽略
 44         int p=0;
 45         for(int i=0;i<x;i++){
 46             p=p*10+ne[i];
 47         }
 48         num[nn++]=p;
 49     }while(next_permutation(ne,ne+x));
 50     return nn;
 51 }
 52 
 53 void dfs(int x,int pre){
 54     if(x==n/2){
 55         int y=n-n/2;//另一半
 56         for(int i=0,j=0;j<y;i++){
 57             if(!vis[i]){
 58                 b[j++]=num[i];
 59             }
 60         }
 61         int ta[11],tb[11];//暂存的a和b
 62         int ra[130],rb[130];//保存组成的整数
 63         int ran=make_permutation(x,a,ta,ra);
 64         int rbn=make_permutation(y,b,tb,rb);
 65         for(int i=0;i<ran;i++){
 66             int p=lower_bound(rb,rb+rbn,ra[i])-rb;
 67             if(rb[p]==ra[i]){//特殊处理
 68                 ans=min(ans,0);
 69             }
 70             else if(p==0){//特殊处理
 71                 ans=min(ans,abs(rb[p]-ra[i]));
 72             }
 73             else if(p==rbn){//特殊处理
 74                 ans=min(ans,abs(rb[p-1]-ra[i]));
 75             }
 76             else{
 77                 ans=min(ans,min(abs(rb[p-1]-ra[i]),abs(rb[p]-ra[i])));
 78             }
 79         }
 80         return ;
 81     }
 82     for(int i=pre;i<n;i++){
 83         if(!vis[i]){
 84             vis[i]=1;
 85             a[x]=num[i];
 86             dfs(x+1,i+1);
 87             vis[i]=0;//回溯
 88         }
 89     }
 90 }
 91 
 92 
 93 int main() {
 94     iostream::sync_with_stdio(false);
 95 
 96 #ifndef ONLINE_JUDGE
 97     freopen("data.in","r",stdin);
 98     //freopen("data.out","w",stdout);
 99 #endif
100 
101     int t;
102     cin>>t;
103     cin.get();
104     while(t--) {
105         getline(cin,str);
106         stringstream ss(str);
107         n=0,ans=inf;
108         memset(vis,0,sizeof(vis));
109         while(ss>>num[n]){
110             n++;
111         }
112                 //因为小于10的数,单个0不算前导,特殊考虑
113                 //并且只有在2个数的时候才会出现这种情况,很容易发现
114         if(n==2){
115             cout<<abs(num[0]-num[1])<<endl;
116             continue;
117         }
118         dfs(0,0);
119         cout<<ans<<endl;
120     }
121     return 0;
122 }    

 

(暴力+深搜)POJ - 2718 Smallest Difference

标签:

原文地址:http://www.cnblogs.com/tak-fate/p/5774869.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!