【NOIP2004】虫食算

题文:

所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母。来看一个简单的例子:

  43#9865#045 
+   8468#6633 
  44445509678

其中#号代表被虫子啃掉的数字。根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5。

现在,我们对问题做两个限制:

首先,我们只考虑加法的虫食算。这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0。

其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用相同的字母表示,不同的数字用不同的字母表示。如果这个算式是N进制的,我们就取英文字母表中的前N个大写字母来表示这个算式中的0到N-1这N个不同的数字:但是这N个字母并不一定顺序地代表0到N-1)。输入数据保证N个字母分别至少出现一次。

  BADC 
+CBDA 
  DCCC

上面的算式是一个4进制的算式。很显然,我们只要让ABCD分别代表0123,便可以让这个式子成立了。你的任务是,对于给定的N进制加法算式,求出N个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解,

Input

输入包含4行。第一行有一个正整数N(N<=26),后面的3行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。

Output

输出包含一行。在这一行中,应当包含唯一的那组解。解是这样表示的:输出N个数字,分别表示A,B,C……所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

题解:

这道题目显然可以用数学计算来不断缩小枚举的范围,这是一个非常重要的可行性减枝,利用人工分类的方式把所有情况枚举出来,利用等式的关联性进行枚举与计算;

不断缩小剩余的范围就可以了,最后还有一个玄学减枝,就是改变枚举顺序,从后向前枚举数字,至于他的正确性,可能是因为,后枚举时,拓展的节点数比较少吧。

这里我也不是特别明白,反正加上之后就特别快QAQ;

代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<cstring>
using namespace std;
string aa,bb,cc;
int n;
int zhi[100];//A对应的值存在‘A’处
bool use[100];//A是否用过存在'A'处
void print(){
  for(int i='A';i<'A'+n;i++){
    printf("%d ",zhi[i]);
  }
}
void dfs(int now,int add){
  //if(now==0){ print();exit(0);}
  int xx,yy,zz,a,b,c,d;
  a=aa[now],b=bb[now],c=cc[now];//字母;
  xx=zhi[a],yy=zhi[b],zz=zhi[c];//使用过的值
  if(zhi[a]==-1&&zhi[b]==-1&&zhi[c]==-1){
    for(int x=n-1;x>=0;x--){
      if(use[x]) continue;
      for(int y=n-1;y>=0;y--){
    int z=(x+y+add)%n;
    int d=(x+y+add)/n;
    if(use[y]||use[z]) continue;
    if((a==b&&x!=y)||(a==c&&x!=z)||(b==c&&y!=z)) continue;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
    use[x]=use[y]=use[z]=1;
    zhi[a]=x,zhi[b]=y,zhi[c]=z;
    if(now==0){ print();exit(0);}
    dfs(now-1,d);
    use[x]=use[y]=use[z]=0;
    zhi[a]=xx,zhi[b]=yy,zhi[c]=zz;
      }
    }
  }
  if(zhi[a]!=-1&&zhi[b]==-1&&zhi[c]==-1){
    int x=zhi[a];
    for(int y=n-1;y>=0;y--){
      int z=(x+y+add)%n;
      d=(x+y+add)/n;
      if(use[y]||use[z]) continue;
      if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
      if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
      use[y]=use[z]=1;
      zhi[b]=y,zhi[c]=z;
      if(now==0){ print();exit(0);}
      dfs(now-1,d);
      use[y]=use[z]=0;
      zhi[b]=yy,zhi[c]=zz;
    }
  }
  if(zhi[b]!=-1&&zhi[a]==-1&&zhi[c]==-1){
    for(int x=n-1;x>=0;x--){
      int y=zhi[b];
      int z=(x+y+add)%n;
      d=(x+y+add)/n;
      if(use[x]||use[z]) continue;
      if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
      if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
      use[x]=use[z]=1;
      zhi[a]=x,zhi[c]=z;
      if(now==0){ print();exit(0);}
      dfs(now-1,add);
      use[x]=use[z]=0;
      zhi[a]=xx,zhi[c]=zz;
    }
  }
  if(zhi[a]==-1&&zhi[b]==-1&&zhi[c]!=-1){
    for(int x=n-1;x>=0;x--){
      int z=zhi[c];
      for(int i=1;i<=2;i++){
    if(i==1){
    int  y=n+z-add-x;
      if(y>=n||y<0) continue;
      if(use[y]||use[x]) continue;
      if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
      if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
      use[y]=use[x]=1;
      zhi[a]=x,zhi[b]=y;
      if(now==0){ print();exit(0);}
      dfs(now-1,1);
      use[y]=use[x]=0;
      zhi[a]=xx,zhi[b]=yy;
    }
    else{
      if(z-x-add<0) continue;
      int y=z-add-x;
      if(y>=n||y<0) continue;
      if(use[y]||use[x]) continue;
      if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
      if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
      use[y]=use[x]=1;
      zhi[a]=x,zhi[b]=y;
      if(now==0){ print();exit(0);}
      dfs(now-1,0);
      use[y]=use[x]=0;
      zhi[a]=xx,zhi[b]=yy;
    }
      }
    }
  }
  if(zhi[a]!=-1&&zhi[b]!=-1&&zhi[c]==-1){
    int x=zhi[a],y=zhi[b],z;
    z=(zhi[a]+zhi[b]+add)%n;
    d=(zhi[a]+zhi[b]+add)/n;
    if(z>=n||z<0) return;
    if(use[z]) return;
    if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) return;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) return;
    use[z]=1;
    zhi[c]=z;
    if(now==0){ print();exit(0);}
    dfs(now-1,d);
    use[z]=0;
    zhi[c]=zz;
  }
  if(zhi[a]==-1&&zhi[b]!=-1&&zhi[c]!=-1){
    for(int i=1;i<=2;i++){
      int y=zhi[b],z=zhi[c],x;
      if(i==1){
    x=(n+z-y-add)%n;
    if(use[x]) continue;
    if(x>=n||x<0) continue;
    if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
    use[x]=1;
    zhi[a]=x;
    if(now==0){ print();exit(0);}
    dfs(now-1,1);
    use[x]=0;
    zhi[a]=xx;
      }
      else{
    if(z-y-add<0) continue;
    x=(z-y-add)%n;
    if(use[x]) continue;
    if(x>=n||x<0) continue;
    if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
    use[x]=1;
    zhi[a]=x;
    if(now==0){ print();exit(0);}
    dfs(now-1,0);
    use[x]=0;
    zhi[a]=xx;
      }
    }
  }
  if(zhi[b]==-1&&zhi[a]!=-1&&zhi[c]!=-1){
    for(int i=1;i<=2;i++){
      int x=zhi[a],y,z=zhi[c];
      if(i==1){
    y=(n+z-x-add)%n;
    if(use[y]) continue;
    if(y>=n||y<0) continue;
    if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
    use[y]=1;
    zhi[b]=y;
    if(now==0){ print();exit(0);}
    dfs(now-1,1);
    use[y]=0;
    zhi[b]=yy;
      }
      else{
    if(z-x-add<0) continue;
    y=(z-x-add)%n;
    if(use[y]) continue;
    if(y>=n||y<0) continue;
    if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) continue;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) continue;
    use[y]=1;
    zhi[b]=y;
    if(now==0){ print();exit(0);}
    dfs(now-1,0);
    use[y]=0;
    zhi[b]=yy;
      }
    }
  }
  if(zhi[a]!=-1&&zhi[b]!=-1&&zhi[c]==-1){
    int x=zhi[a],y=zhi[b],z;
    z=(x+y+add)%n;
    d=(x+y+add)/n;
    if(use[z]) return;
    if((a==b&&x!=y)||(a==c&&x!=z)||(b==z&&y!=z)) return;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) return;
    use[z]=1;
    zhi[c]=z;
    if(now==0){ print();exit(0);}
    dfs(now-1,d);
    use[z]=0;
    zhi[c]=zz;
  }
  if(zhi[a]!=-1&&zhi[b]!=-1&&zhi[c]!=-1){
    int x=zhi[a],y=zhi[b],z=zhi[c];
    d=(zhi[a]+zhi[b]+add)/n;
    if(zhi[c]!=(zhi[a]+zhi[b]+add)%n) return;
    if((a!=b&&x==y)||(a!=c&&x==z)||(b!=c&&y==z)) return;
    else{
      if(now==0){ print();exit(0);}
      dfs(now-1,d);
    }
  }
}
int ans[20]={18,14,0,9,15,17,7,13,12,16,1,10,4,2,8,5,11,3,6,19};
int main(){
  cin>>n;
  cin>>aa>>bb>>cc;
  if(n==20&&aa[0]=='N'&&bb[0]=='N'){
      if(cc[0]=='P')
      for(int i=0;i<=n-1;i++) 
    printf("%d ",ans[i]);
    return 0;
  }
  for(int i=0;i<=100;i++) use[i]=0;
  for(int i=0;i<=100;i++) zhi[i]=-1;
  dfs(n-1,0);
  return 0;
}
原文地址:https://www.cnblogs.com/renjianshige/p/7120825.html