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

原题链接:

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 }    
时间: 2024-08-03 21:07:39

(暴力+深搜)POJ - 2718 Smallest Difference的相关文章

POJ 2718 Smallest Difference(贪心 or next_permutation暴力枚举)

Smallest Difference Description Given a number of distinct decimal digits, you can form one integer by choosing a non-empty subset of these digits and writing them in some order. The remaining digits can be written down in some order to form a second

POJ 2718 Smallest Difference 未AC 《挑战程序设计竞赛》

题目:POJ 2718 思路: 分为奇数和偶数两种情况进行处理,输入个数为奇数的时候,无须穷举,最小差是一定的,如0 1 2 3 4,最小差为102 - 43. 输入个数为偶数的时候,用next_permutation穷举. 没有AC-- 1 #include <iostream> 2 #include <algorithm> 3 #include <iostream> 4 #include <stdio.h> 5 #include <string.h

poj 2718 Smallest Difference(暴力枚举)(贪心待补充)

abs写成fabs导致WA了一发. 关于next_permutation()这个STL里面的函数的基本应用 http://www.cnblogs.com/luosuo10/p/5479188.html 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 using namespace s

poj 2718 Smallest Difference(穷竭搜索dfs)

Description Given a number of distinct decimal digits, you can form one integer by choosing a non-empty subset of these digits and writing them in some order. The remaining digits can be written down in some order to form a second integer. Unless the

poj 2718 Smallest Difference

题目大意:给你几个数字,选出一些数字组成一个整数,另外的组成另一个整数,求这两个数差的绝对值的最小值 Input The first line of input contains the number of cases to follow. For each case, there is one line of input containing at least two but no more than 10 decimal digits. (The decimal digits are 0,

POJ 2718 Smallest Difference (穷竭搜索)

http://poj.org/problem?id=2718 将一个数切一刀拆成两个数,两个数每一位数字的顺序都可改变,但是不能有前导0.求这两个数之差的最小值. 我使用了搜索并且避免了递归,自认为是比较好的算法. 一开始我想到的是枚举,并且很快给出了实现: #ifndef ONLINE_JUDGE #pragma warning(disable : 4996) #endif #include <iostream> #include <string> #include <al

穷竭搜索: POJ 2718 Smallest Difference

题目:http://poj.org/problem?id=2718 题意: 就是输入N组数据,一组数据为,类似 [1  4  5  6  8  9]这样在0~9之间升序输入的数据,然后从这些数据中切一刀,比如  n1:[1 4 5],n2:[6 8 9]这样,然后 abs(n1- n2),对n1 和 n2的所有可能的排列 n1: [1 4 5][1 5 4]...这样,要算出来的最小的差,显然从中间切一刀才会出现这种解. 题解: 这里可以用来练习 STL,算法不会也没有关系,可以在这题学到 bi

POJ - 2718 Smallest Difference(全排列)

题意:将n个数字分成两组,两组分别组成一个数字,问两个数字的最小差值.要求,当组内数字个数多于1个时,组成的数字不允许有前导0.(2<=n<=10,每个数字范围是0~9) 分析: 1.枚举n个数字的全排列. 2.当两组数字个数相同或只差1时组成的两个数字才可能出现最小差值. 3.0~cnt/2 - 1为前半组数字,cnt/2~cnt-1为后半组数字. 4.注意getchar()的位置. #pragma comment(linker, "/STACK:102400000, 102400

HDU 4876 ZCC loves cards【暴力+深搜+剪枝】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4876 题意:给你N,l,k三个数,N代表N个数,从中任选k个数,然后 这k个数组成一个环,可以从这个环中选连续的1-k个数进行异或和 ,把所得到的值填充到l的后面,使得有一个数r让l-r之间所有的整 整数都被这些异或和填满,求最大的r,也许表达的不太清楚,其实 就是找一个最大的r,使得给定的l到这个r之间所有的数都能够被这些 异或和表示出来,注意异或和要求是连续的数异或的和. 分析:这道题我看了好久