Problem 1161 : Verbal Arithmetic

問題概要

日本語なので本文参照。(http://rose.u-aizu.ac.jp/onlinejudge/ProblemSet/description.jsp?id=1161&lang=jp


ACM + IBM = ICPC
のような覆面算の答えの総数を求めよ。

  • 一つのアルファベットには0〜9の一つの数字が対応する
  • 異なるアルファベットには異なる数字が対応する
  • 出現するアルファベットの数は10以下
  • 一桁の数の場合を除いて、数の先頭の0は許されない

解法

まずはそれぞれのアルファベット毎の係数を求める。
それぞれのアルファベットに対して割り当てる数字を、深さ優先探索で順に決めていく。


全く枝刈りをしない解法では9s弱となりTLE。
正の係数には全て9を入れても足りないor負の係数に全て9を入れても大きい場合に枝刈りをすると6.5s程度で通った。

ソースコード

int n;
char in[12][9];
int m,ans,id[256];
pi co[10];
bool use[10];

void rec(int c,int s)
{
	int big=s,sml=s;
	for(int i=c;i<m;i++)
	{
		if(co[i].first<0)sml+=9*co[i].first;
		else big+=9*co[i].first;
	}
	if(sml>0||big<0)return;
	
	if(c==m)
	{
		ans++; return;
	}
	rep(i,10)if(!use[i]&&!(co[c].second&&i==0))
	{
		use[i]=1;
		rec(c+1,s+co[c].first*i);
		use[i]=0;
	}
}
int main()
{
	while(scanf("%d",&n),n)
	{
		rep(i,n)scanf("%s",in[i]);
		rep(i,256)id[i]=-1;
		rep(i,10)co[i]=mp(0,0),use[i]=0;
		ans=m=0;
		
		rep(i,n)
		{
			int t=i<n-1?1:-1,len=strlen(in[i]);
			for(int j=len-1;j>=0;j--)
			{
				char c=in[i][j];
				if(id[c]<0)id[c]=m++;
				co[id[c]].first+=t;
				if(j==0&&len>1)co[id[c]].second=1;
				t*=10;
			}
		}
		sort(co,co+m,greater<pi>());
		
		rec(0,0);
		printf("%d\n",ans);
	}
	return 0;
}