http://poj.org/problem?id=2718
将一个数切一刀拆成两个数,两个数每一位数字的顺序都可改变,但是不能有前导0。求这两个数之差的最小值。
我使用了搜索并且避免了递归,自认为是比较好的算法。
一开始我想到的是枚举,并且很快给出了实现:
#ifndef ONLINE_JUDGE #pragma warning(disable : 4996) #endif #include <iostream> #include <string> #include <algorithm> using namespace std; ///////////////////////////SubMain////////////////////////////////// int main(int argc, char *argv[]) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int n; cin >> n; cin.ignore(); while (n--) { string all; getline(cin, all); all.erase(remove(all.begin(), all.end(), ' '), all.end()); int result = 0x3F3F3F3F; int cut = all.size() / 2; do { string s1 = all.substr(0, cut); string s2 = all.substr(cut); if ((s1[0] == '0' && s1.size() > 1) || (s2[0] == '0' && s2.size() > 1) ) { continue; } int n1 = atoi(s1.c_str()); int n2 = atoi(s2.c_str()); int dif = abs(n1 - n2); if (dif < result) { result = dif; } } while (next_permutation(all.begin(), all.end())); cout << result << endl; } #ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout); system("out.txt"); #endif return 0; } ///////////////////////////End Sub//////////////////////////////////
没料到TLE,后来想了想,这里的复杂度是O((length!)n),当length = 10 的时候内层最高达到了3628800 次循环,而用例则可能是很多的。
要优化得下点功夫,起先想到改用模拟的方法,分奇偶讨论,可是这道题目是放在2.1 最基础的“穷竭搜索” 穷竭搜索这节里,目的是训练搜索算法。
于是继续走搜索的路线,上面的程序之所以慢,是因为重复计算。比如第一个字串为12,第二个字串为34这种情况和第一个字串为34,第二个字串为12这种情况被视作不同的情况。这是应当被优化的第一个点。
第二个点是string类型的全排操作比较费时,可以用位运算优化。
我看到有些人用dfs递归,感觉很别扭,代码一不好理解,二浪费栈。
我使用了我最喜欢的玩具bitset:
#ifndef ONLINE_JUDGE #pragma warning(disable : 4996) #endif #include <iostream> #include <string> #include <algorithm> #include <bitset> using namespace std; ///////////////////////////SubMain////////////////////////////////// int main(int argc, char *argv[]) { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int n; cin >> n; cin.ignore(); while (n--) { string all; getline(cin, all); all.erase(remove(all.begin(), all.end(), ' '), all.end()); int length = all.size(); int cut = length / 2; int permute = 1 << length; int result = 0x3F3F3F3F; do { bitset<10> used = static_cast<bitset<10>>(permute); string s1, s2; for (int i = 0; i < length; ++i) { if (used[i]) { s1 += all[i]; } else { s2 += all[i]; } } if (s1.size() != cut) { continue; } if (s1[0] == '0' && s1.size() > 1) { continue; } // s1 s2 已经被切割出来了 // 穷举它们 do { int n1 = atoi(s1.c_str()); do { if (s2[0] == '0' && s2.size() > 1) { continue; } int n2 = atoi(s2.c_str()); int dif = abs(n1 - n2); //cout << s1 << ' ' << s2 << " dif " << dif << " result: " << result << endl; if (dif < result) { result = dif; } } while (next_permutation(s2.begin(), s2.end())); } while (next_permutation(s1.begin(), s1.end())); } while (--permute); cout << result << endl; } #ifndef ONLINE_JUDGE fclose(stdin); fclose(stdout); system("out.txt"); #endif return 0; } ///////////////////////////End Sub//////////////////////////////////不对,不对,大家很难看懂吧,为了这段代码,笔者也学了很多东西,但是还是觉得太繁琐!因此又补了一份代码!
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define INF 0x3f3f3f3f using namespace std; int a[15]; int n; void solve() { while(a[0]==0) next_permutation(a,a+n); int ans=INF; int mid=(n+1)/2; do { if(a[mid]) { int x=a[0],y=a[mid]; for(int i=1;i<mid;i++) x=x*10+a[i]; for(int i=mid+1;i<n;i++) y=y*10+a[i]; if(ans>abs(x-y)) ans=abs(x-y); } }while(next_permutation(a,a+n)); cout<<ans<<endl; } int main() { int T; char c; scanf("%d",&T); getchar(); while(T--) { n=0; memset(a,0,sizeof(a)); while((c=getchar())!='\n') { if(c!=' ') a[n++]=c-'0'; } if(n==1) printf("%d\n",a[0]); else if(n==2) printf("%d\n",abs(a[1]-a[0])); else solve(); } return 0; }
#include #include #include #include using namespace std; const int MAX_N = 11; int ans, n; int a[MAX_N], b[MAX_N]; bool used[MAX_N]; void solve(int aa) { int m = 0; for (int i = 0; i < n; ++ i) { if (!used[i]) { b[m++] = a[i]; } } do { int bb = 0; for (int i = 0; i < m; ++ i) { bb = bb*10 + b[i]; } if (b[0] != 0 || m == 1) { ans = min(ans, abs(aa - bb)); } }while(next_permutation(b, b + m)); } void dfs(int k, int r) { if (k == n/2) { solve(r); } else { for (int i = 0; i < n; ++ i) { if (!used[i]) { if (a[i] == 0 && k == 0 && n > 3) continue; used[i] = true; dfs(k+1, r*10+a[i]); used[i] = false; } } } } int main() { #ifndef ONLINE_JUDGE freopen("input.in", "r", stdin); #endif int t; scanf("%d\n", &t); char str[25]; while(t --) { gets(str); n = 0; for (int i = 0; str[i] != '\0'; ++ i) { if(str[i] >= '0' && str[i] <= '9') { a[n++] = str[i] - '0'; } } memset(used, false, sizeof(used)); ans = INT_MAX; dfs(0, 0); printf("%d\n", ans); } return 0; }
POJ 2718 Smallest Difference (穷竭搜索)
原文地址:http://blog.csdn.net/acm_10000h/article/details/40949011