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;
}
原文地址:https://www.cnblogs.com/scau20110726/p/2979473.html