poj 3548 Restoring the digits

暴力+模拟

题意:一行字符串没有空格,是一个加法或减法算术表达式。数字中有大写字母,大写字母代表了某个数字,一个字母只能代表1种数字,不同字母代表的数字不同,另外允许存在前导0,另外字母总数最多10个。另外题目中说第1个数字要大于等于第2个数字,所以我做了判断,然后wa了一个早上+一个晚上,注释掉就AC了很无语。。。。

另外答案可能有多种,任意一种都可以的,至少我的代码是这样,并且保证是有解的。另外这题网上找不到题解的,确实我也觉得这题很无聊。。。

但是选拔赛的时候,居然想成了拓扑排序(因为做过类似的,又一次被驴舔了)

说说做法吧

因为字母最多十个,所以就暴力枚举,可想而知枚举量最大是10!,枚举后就把3个数字都先转化为int型,不要在数组里面模拟相加相减还进位什么的,这样子其实更容易错。如果一旦找到符合条件的就跳出了,否则会超时

另一个枚举是用二进制和next_permutation,最多是10个字母,所以最大状态是1023,转为二进制看有多少个1,但1的个数和字母个数相同就是我们要的,好像1010,有两个1,分别在3和1,所以我们就要3,1,分别对应两个字母的数值,然后3,1还不够我们还要枚举全排列才能考虑所有情况,接着后面的做法就是一样的了

 

然后看代码吧,代码是dfs版本和next_permutation版本的都有了,其实都差不多

 

dfs

#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;

#define N 20

#define MAX 3628810



char s[3][N],op;

int n[3][N],len[3];

int num;

struct cha

{

   char c;

   int n;

}a[N];

bool number[10];

bool OK;



void init(char *tmp)

{

   bool used[2*N];

   memset(n,0,sizeof(n));

   memset(s,0,sizeof(s));

   memset(a,0,sizeof(a));

   memset(used,0,sizeof(used));

   num=0;

   int i,j,k;

   for(i=0,j=0; i<3; i++)

   {

      len[i]=j;

      for(k=0;;j++,k++)

      {

         if(tmp[j]=='+' || tmp[j]=='-' || tmp[j]=='=' || tmp[j]=='\0')

            break;

         s[i][k]=tmp[j];

         if(tmp[j]>='0' && tmp[j]<='9') n[i][k]=tmp[j]-'0';

         else

         {

            n[i][k]=tmp[j]-'A'+26;

            if(!used[tmp[j]-'A'])

            {

               used[tmp[j]-'A']=true;

               a[num++].c=tmp[j];

            }

         }

      }

      s[i][k]='\0';

      if(i==0) op=tmp[j];

      len[i]=j-len[i];

      j++;

   }

}



int tran(int i)

{

   int ans=0;

   for(int k=0; k<len[i]; k++)

      ans=ans*10+n[i][k];

   return ans;

}



void cal()

{

   for(int i=0; i<3; i++)

      for(int j=0; j<len[i]; j++)

         if(s[i][j]>='A' && s[i][j]<='Z')

            for(int k=0; k<num; k++)

               if(s[i][j] == a[k].c)

                  n[i][j]=a[k].n;



   int ss[3];

   for(int i=0; i<3; i++)

      ss[i]=tran(i);

   if(op=='+' && ss[0]+ss[1]==ss[2]) OK=true;

   if(op=='-' && ss[0]-ss[1]==ss[2]) OK=true;

}



void dfs(int c)

{

   if(c>=num) //枚举结束

   {

      cal();

      return ;

   }

   for(int i=0; i<10; i++) if(!number[i])

   {

      number[i]=true;

      a[c].n=i;

      dfs(c+1);

      if(OK) return ;

      number[i]=false;

   }

}



int cmp(struct cha p ,struct cha q)

{

   return p.c < q.c;

}



void solve()

{

   OK=false;

   sort(a,a+num,cmp);

   memset(number,false,sizeof(number));

   dfs(0);

   if(!OK)

   for(int i=0; i<num; i++)

      printf("%c %d\n",a[i].c,a[i].n);

}



int main()

{

   char tmp[3*N];

   while(scanf("%s",tmp)!=EOF)

   {

      init(tmp);

      solve();

   }

   return 0;

}

 

stl

#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;

#define N 20

#define MAX 3628810



char s[3][N],op;

int n[3][N],len[3];

int num;

struct cha

{

   char c;

   int n;

}a[N];

bool OK;



void init(char *tmp)

{

   bool used[2*N];

   memset(n,0,sizeof(n));

   memset(s,0,sizeof(s));

   memset(a,0,sizeof(a));

   memset(used,0,sizeof(used));

   num=0;

   int i,j,k;

   for(i=0,j=0; i<3; i++)

   {

      len[i]=j;

      for(k=0;;j++,k++)

      {

         if(tmp[j]=='+' || tmp[j]=='-' || tmp[j]=='=' || tmp[j]=='\0')

            break;

         s[i][k]=tmp[j];

         if(tmp[j]>='0' && tmp[j]<='9') n[i][k]=tmp[j]-'0';

         else

         {

            n[i][k]=tmp[j]-'A'+26;

            if(!used[tmp[j]-'A'])

            {

               used[tmp[j]-'A']=true;

               a[num++].c=tmp[j];

            }

         }

      }

      s[i][k]='\0';

      if(i==0) op=tmp[j];

      len[i]=j-len[i];

      j++;

   }

}





int tran(int i)

{

   int ans=0;

   for(int k=0; k<len[i]; k++)

      ans=ans*10+n[i][k];

   return ans;

}



void solve(int *per)

{

   sort(per,per+num); //全排列前记得排序

   do //对per枚举全排列

   {

      for(int i=0; i<num; i++) a[i].n=per[i];



      for(int i=0; i<3; i++)

         for(int j=0; j<len[i]; j++)

            if(s[i][j]>='A' && s[i][j]<='Z')

               for(int k=0; k<num; k++)

                  if(s[i][j] == a[k].c)

                     n[i][j]=a[k].n;



      int ss[3];

      for(int i=0; i<3; i++)

         ss[i]=tran(i);

      if(op=='+' && ss[0]+ss[1]==ss[2]) {OK=true; break;}

      if(op=='-' && ss[0]-ss[1]==ss[2]) {OK=true; break;}





   }

   while(next_permutation(per,per+num));

}



int cmp(struct cha p ,struct cha q)

{

   return p.c < q.c;

}



void BF()

{

   int per[20];

   OK=false;

   sort(a,a+num,cmp);

   for(int state=0; state<1024; state++)

   {

      int cc=0;

      for(int k=0; k<10; k++) if(state&(1<<k)) per[cc++]=k;

      if(cc==num) //1的个数和

         solve(per);

      if(OK) break;

   }

   for(int i=0; i<num; i++) printf("%c %d\n",a[i].c,a[i].n);

}



int main()

{

   char tmp[3*N];

   while(scanf("%s",tmp)!=EOF)

   {

      init(tmp);

      BF();

   }

   return 0;

}

 

你可能感兴趣的:(REST)