POJ 2718【permutation】
问题描述:
给一串数,求划分后一个子集以某种排列构成一个数,余下数以某种排列构成另一个数,求这两个数最小的差,注意0开头的处理。
超时问题:一开始是得到一个数列的组合之后再从中间进行切割得到两数,会超时。后来采用的方法是将前面的数在DFS中得到固定,在函数work中对后面(n-n/2)个数进行排列组合。
针对整个数列的dfs排列组合剪枝,若当前搜索的第二个数后面全部补零与第一个数所产生的差值比当前所搜索到的结果还要大,那么就直接返回。这个剪枝就是超时与几十MS的差距
int nums[10]={1,10,100,1000,10000,100000,1000000};
解法一:朴素permutation
#include <iostream> #include <algorithm> #include <map> #include <string> #include <string.h> #include <ctype.h> #include <vector> #include <math.h> using namespace std; char s[1000]; int t; int main() { cin>>t; getchar(); while(t--) { int a[11],num=0,ans=0x7f7f7f; gets(s); for(int i=0;i<strlen(s);i++) if (s[i] >= '0'&&s[i] <= '9')//删除空格 a[num++]=s[i]-'0'; sort(a,a+num); do { int num1=0,num2=0; //前面那个数的首位不能是0,后面那个数的首位也不能是0,还有当为输入是10时,要么前面那个数的是0,要么后面的那个数是0,所以条件num>2加"||"前后都一样 if(!a[0]||(!a[num/2] && num>2))continue; for(int i=0;i<num/2;i++)num1=num1*10+a[i]; for(int i=num/2;i<num;i++)num2=num2*10+a[i]; ans=min(ans,abs(num1-num2)); }while(next_permutation(a, a+num)); cout<<ans<<endl; } return 0; }
解法二:dfs+permutation
#include <cstdio> #include <cstring> #include <cmath> #include <algorithm>//next_permutation包含其中 using namespace std; int a[15], vis[15], n, ans, aa, bb; void solve(int aa) { int len = 0, flag = 1, b[15]; bb = 0; for(int i = 0; i < n; i++) if(!vis[i]) b[len++] = a[i]; for(int i = 0; i < len; i++) { if(i == 0 && b[i] == 0) flag = 0; bb = bb * 10 + b[i]; } if(flag) ans = min(ans, abs(aa-bb)); while(next_permutation(b, b+len)) { bb = 0; flag = 1; for(int i = 0; i < len; i++) { if(i == 0 && b[i] == 0) flag = 0; bb = bb * 10 + b[i]; } if(flag) ans = min(ans, abs(aa-bb)); } return; } void dfs(int k, int res) { if(k == n/2) { solve(res); return; } for(int i = 0; i < n; i++) { if(!vis[i]) { if(a[i] == 0 && k == 0) continue; vis[i] = 1; dfs(k+1, res*10+a[i]); vis[i] = 0; } } return; } int main() { int kase; scanf("%d", &kase); getchar(); while(kase--) { n = 0; char ch; memset(a, 0, sizeof(a)); memset(vis, 0, sizeof(vis)); while((ch = getchar()) != '\n') { if(ch == ' ') continue; else a[n++] = ch - '0'; } if(n == 2 && a[0] == 0) { //当只有两个数字,且其中一个为0时,特殊处理 printf("%d\n", a[1]-a[0]); continue; } ans = 1 << 30; dfs(0, 0); printf("%d\n", ans); } return 0; }