luogu P1092 虫食算

https://www.luogu.org/problem/P1092

题目描述

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

 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个不同的字母分别代表的数字,使得该加法算式成立。输入数据保证有且仅有一组解。

输入格式

包含四行。
第一行有一个正整数N(N≤26)。

后面的三行,每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这3个字符串左右两端都没有空格,从高位到低位,并且恰好有N位。

输出格式

一行,即唯一的那组解。

解是这样表示的:输出N个数字,分别表示A,B,C,…所代表的数字,相邻的两个数字用一个空格隔开,不能有多余的空格。

输入输出样例

输入 #1

5
ABCED
BDACE
EBBAA

输出 #1

1 0 3 4 2

说明/提示

对于30%的数据,保证有N≤10;

对于50%的数据,保证有N≤15;

对于全部的数据,保证有N≤26。

代码

#include<algorithm>
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;

int i,n;
char ch,gl[2],a[27],b[27],c[27];
int ans[27];
bool used[27];

void read()
{
    scanf("%d",&n);
    gets(gl);
    for (i=n; i>=1; i--)
      scanf("%c",&a[i]);
    gets(gl);
    for (i=n; i>=1; i--)
      scanf("%c",&b[i]);
    gets(gl); 
    for (i=n; i>=1; i--)
      scanf("%c",&c[i]);    
}
void update(int k, int which, int value)
{
    used[value]=1;
    if (which==1) ans[a[k]-'A']=value;
    if (which==2) ans[b[k]-'A']=value;
    if (which==3) ans[c[k]-'A']=value;    
}
void goback(int k, int which, int value)
{
    used[value]=0;
    if (which==1) ans[a[k]-'A']=-1;
    if (which==2) ans[b[k]-'A']=-1;
    if (which==3) ans[c[k]-'A']=-1;    
}
int judge1(int k, int jw, int &newjz, int &which, int &value)
{
    int cnt=0;
    if (ans[a[k]-'A']>=0) cnt++;
    if (ans[b[k]-'A']>=0) cnt++;
    if (ans[c[k]-'A']>=0) cnt++;
    if (cnt<2) return -1;
    if (cnt==3){
        if ((ans[a[k]-'A']+ans[b[k]-'A']+jw)%n!=ans[c[k]-'A'])
          return 0;
        newjz=(ans[a[k]-'A']+ans[b[k]-'A']+jw)/n;
        return 1;
    }
    if (ans[c[k]-'A']<0)
    {
        int tmp=ans[a[k]-'A']+ans[b[k]-'A']+jw;
        if (used[tmp%n]) return 0;
        newjz=tmp/n;
        which=3; value=tmp%n;
        return 1;
    }
    if (ans[a[k]-'A']<0)
    {
        int tmp=ans[c[k]-'A']-ans[b[k]-'A']-jw,tmp1=(tmp+n)%n;
        if (used[tmp1]) return 0;
        newjz=tmp1!=tmp;
        which=1; value=tmp1;
        return 1;
    }
    if (ans[b[k]-'A']<0)
    {
        int tmp=ans[c[k]-'A']-ans[a[k]-'A']-jw,tmp1=(tmp+n)%n;
        if (used[tmp1]) return 0;
        newjz=tmp1!=tmp;
        which=2; value=tmp1;
        return 1;
    }
}
bool judge2(int k)
{    
    int cnt=0;
    if (ans[a[k]-'A']>=0) cnt++;
    if (ans[b[k]-'A']>=0) cnt++;
    if (ans[c[k]-'A']>=0) cnt++;
    if (cnt<2) return 1;
    if (cnt==3)
    {
        int tmp=ans[a[k]-'A']+ans[b[k]-'A'];
          if (tmp%n!=ans[c[k]-'A'] && (tmp+1)%n!=ans[c[k]-'A']) return 0;
          return 1;
    }
    if (ans[c[k]-'A']<0)
    {
        int tmp=(ans[a[k]-'A']+ans[b[k]-'A'])%n;
        if (used[tmp]&&used[(tmp+1)%n]) return 0;
        return 1;
    }
    if (ans[a[k]-'A']<0)
    {
        int tmp=(ans[c[k]-'A']-ans[b[k]-'A']+n)%n;
        if (used[tmp]&&used[(tmp-1+n)%n]) return 0;
        return 1;
    }
    if (ans[b[k]-'A']<0)
    {
        int tmp=(ans[c[k]-'A']-ans[a[k]-'A']+n)%n;
        if (used[tmp]&&used[(tmp-1+n)%n]) return 0;
        return 1;
    }
}
void dfs(int k, int jw)
{
    if (k>n){
        for (int i=0; i<n-1; i++)
          printf("%d ",ans[i]);
        printf("%d",ans[n-1]);
        exit(0);
    } 
    for (int i=k; i<=n; i++)
      if (judge2(i)==0) return;
    if (ans[a[n]-'A']+ans[b[n]-'A']>=n) return;
    int newjz,which=0,value=-1; 
    int tmp1=judge1(k,jw,newjz,which,value);
    if (tmp1==0) return;
    if (tmp1==1)
    {
        if (which==0)
            dfs(k+1,newjz);
        else 
        {
            update(k,which,value);
            dfs(k+1,newjz);
            goback(k,which,value);
        }
        return;
    }
    if (ans[a[k]-'A']<0) 
    {
        for (int i=0; i<n; i++)
          if (used[i]==0)
          {
              used[i]=1; ans[a[k]-'A']=i;
              int tmp1=judge1(k,jw,newjz,which,value);
              if (tmp1==1) 
              {
                if (which==0)
                    dfs(k+1,newjz);
                else 
                  {
                    update(k,which,value);
                    dfs(k+1,newjz);
                    goback(k,which,value);
                }
                which=0;
              }
              if (tmp1==-1) 
              for (int j=0; j<n; j++)
                if (used[j]==0)
                {
                    used[j]=1; ans[b[k]-'A']=j;
                    int tmp1=judge1(k,jw,newjz,which,value);
                    if (tmp1==1)
                    {
                        if (which==0)
                            dfs(k+1,newjz);
                        else 
                          {
                            update(k,which,value);
                            dfs(k+1,newjz);
                            goback(k,which,value);
                        }    
                        which=0;            
                    }
                    used[j]=0; ans[b[k]-'A']=-1;                    
                }
              used[i]=0; ans[a[k]-'A']=-1;
          }
    }
    else 
    {
        for (int i=0; i<n; i++)
          if (used[i]==0)
          {
              used[i]=1; ans[b[k]-'A']=i;
              if (judge1(k,jw,newjz,which,value)==1)
              {
                if (which==0)
                    dfs(k+1,newjz);
                else 
                  {
                    update(k,which,value);
                    dfs(k+1,newjz);
                    goback(k,which,value);
                }
                which=0;
              }
              used[i]=0; ans[b[k]-'A']=-1;
          }
    }
}
int main()
{
    memset(ans,-1,sizeof(ans));
    read(); 
    dfs(1,0);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值