PKU 2718-Smallest Difference

問題概要

互いの異なる数字(0〜9)が与えられる.
その数値を並べて二つの数字を作るとき,その二つの数値の差の最小値を求めよ.
例:1 2 3の場合12-3=9

解法

全探索(数値の個数<=4)

  • 書くだけ

最良優先探索(数値の個数>4)

  • 最良の場合の差が小さい順に探索

実装(C++)

#include <iostream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <set>
#include <queue>
using namespace std;
int pow10[]={1,10,100,1000,10000,100000};
int n,digits[10];

typedef pair<int,int> P;
struct State{
	int a,b;
	int used;
	int max_dist;
	int min_dist;
	int k;
	State(int a,int b,int used,int k):a(a),b(b),used(used),k(k){
		max_dist=(a-b)*pow10[k]+pow10[k]-1;
		min_dist=(a-b)*pow10[k]+1-pow10[k];
	}
};
bool operator<(const State &a,const State &b){
	return a.min_dist>b.min_dist;
}
int solve(){
	int ans=9999999;
	priority_queue<State> que;
	set<P> ac;
	if(digits[n-1]!=0){
		//個数が2の倍数
		for(int i=0;i<n;i++){
			if(digits[i]==0)continue;
			for(int j=i+1;j<n;j++){
				que.push(State(digits[j],digits[i],(1<<i)|(1<<j),n/2-1));
			}
		}
	}else{
		//個数が2の倍数ではない
		for(int i=0;i<n-1;i++){
			if(digits[i]==0)continue;
			que.push(State(digits[i],digits[n-1],(1<<(n-1)|(1<<i)),n/2-1));
		}
	}
	while(!que.empty()){
		State now=que.top();que.pop();
		if(ans<now.min_dist)break;
		ans=min(ans,now.max_dist);
		//使われていない数から適当に選ぶ
		if(now.used==(1<<n)-1)continue;//もう使える数が無い
		for(int i=0;i<n;i++){
			if((now.used>>i)&1)continue;
			for(int j=0;j<n;j++){
				if(i==j)continue;
				if((now.used>>j)&1)continue;
				//適当に二つの数を選ぶ
				int na=now.a*10+digits[i];
				int nb=now.b*10+digits[j];
				if(ac.find(P(na,nb))==ac.end()){
					ac.insert(P(na,nb));
					que.push(State(na,nb,now.used|(1<<i)|(1<<j),now.k-1));
				}
			}
		}
	}
	return ans;
}
int dfs(int x=-1,int y=-1,int used=0){
	if(used==(1<<n)-1&&x!=-1&&y!=-1){
		return abs(x-y);
	}

	int ans=99999999;
	for(int i=0;i<n;i++){
		if(((used>>i)&1)==0){
			if(x==-1)ans=min(ans,dfs(digits[i],y,used|(1<<i)));
			if(y==-1)ans=min(ans,dfs(x,digits[i],used|(1<<i)));
			if(x>0)ans=min(ans,dfs(x*10+digits[i],y,used|(1<<i)));
			if(y>0)ans=min(ans,dfs(x,y*10+digits[i],used|(1<<i)));
		}
	}
	return ans;
}
int main() {
	int tcase;
	string in;
	getline(cin,in);
	tcase=atoi(in.c_str());
	for(int T=0;T<tcase;T++){
		n=0;getline(cin,in);
		stringstream ss(in);
		while(ss>>digits[n])n++;
		if(n<5){
			cout<<dfs()<<endl;
		}else{
			if(n&1)digits[n++]=0;
			cout<<solve()<<endl;
		}
	}
	return 0;
}