http://poj.org/problem?id=2718
将一个数切一刀拆成两个数,两个数每一位数字的顺序都可改变,但是不能有前导0。求这两个数之差的最小值。
我使用了搜索并且避免了递归,自认为是比较好的算法。
一开始我想到的是枚举,并且很快给出了实现:
#ifndef ONLINE_JUDGE
#pragma warning(disable : 4996)
#endif
#include
#include
#include
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
#include
#include
#include
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>(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
#include
#include
#include
#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;iabs(x-y))
ans=abs(x-y);
}
}while(next_permutation(a,a+n));
cout<
#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;
}