NOIP2004 虫食算

https://www.luogu.org/problem/show?pid=1092

题目描述

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

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行每行有一个由大写字母组成的字符串,分别代表两个加数以及和。这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。

 

最暴力的搜索:枚举每个字母代表什么,检验

 

优化:

O、对于当前列的三个字符是否已经确定分8种情况讨论

(3个都确定,确定2个*3,只确定1个*3,都没确定)

1、3个都确定的,直接判断

2、确定了2个的,推出第3个

3、只确定1个的,枚举一个,推出另一个

4、都没确定的,枚举前两个,推第三个,这样可以不用枚举是否进位

A、对于搜索顺序的优化:

1、小学算竖式?从右往左算! 所以按竖式从右往左枚举,低位的进位对高位有影响

2、枚举字母代表的数字从n-1往小枚举,因为最高位不会进位,高位比较小(优化的关键)

B、一般都能想到的优化:

1、用一个数组,记录这个数字是否已经被用过(代码中的use[])

2、一旦结果搜出来了,设标志变量,一路return之至主函数,最好在每个递归回溯前都写一个。(exit(0)也可以,但不确定NOIP可不可以用)

C、进位的优化:

1、用一个数组记录当前位是否进位,代码中的bit[]

2、如果这一列的左边一列3个数都齐了,判断在满足他们的情况下,这一列是否需要进位

D、剪枝的关键:

枚举这一列左边的列,如果他们3个数都齐了,判断在进位/不进位的情况下是否成立,不成立则return

没有这个剪枝过不了第9个点

 

 注意(我犯的错误):

1、并不是同一列中的三个字母代表数字都不能相同,需要判断一下有没有重复字母

这种情况只会影响确定1个 和 都没确定得到情况

对于只确定1个字母的列,只需要判断枚举出的数是否出现过即可

对于3个字母都没确定的列,在枚举前两个的时候要判断前两个字母是否相等

2、低位往高位进1,高位算的时候不是想当然的10啊,是n,这是n进制

#include<cstdio>
#include<cstring>
#include<algorithm> 
using namespace std;
int n;
char a[30],b[30],c[30];
int ans[30];
bool ok,use[30],bit[30];
inline void dfs(int now)
{
    if(ok) return;
    if(now<0)
    {
        for(int i=0;i<n;i++) printf("%d ",ans[i]);
        ok=true;
        return;
    }
    int flag=2;
    if(now && ans[a[now-1]-'A']!=-1 && ans[b[now-1]-'A']!=-1 && ans[c[now-1]-'A']!=-1) 
    {
        if((ans[a[now-1]-'A']+ans[b[now-1]-'A'])%n==ans[c[now-1]-'A']) flag=0;
        else if((ans[a[now-1]-'A']+ans[b[now-1]-'A']+1)%n==ans[c[now-1]-'A']) flag=1;
        else return;    
    }
    for(int i=now-2;i>=0;i--)
    {
        if(ans[a[i]-'A']!=-1 && ans[b[i]-'A']!=-1 && ans[c[i]-'A']!=-1)
         if((ans[a[i]-'A']+ans[b[i]-'A'])%n!=ans[c[i]-'A'] && (ans[a[i]-'A']+ans[b[i]-'A']+1)%n!=ans[c[i]-'A']) 
          return;
    }
    int & aa=ans[a[now]-'A'],& bb=ans[b[now]-'A'],& cc=ans[c[now]-'A'];
    if(aa!=-1 && bb!=-1  && cc!=-1)
    {
        if((aa+bb+bit[now])%n==cc) 
        {
            bit[now-1]=(aa+bb+bit[now])/n;
            if(flag!=2 && bit[now-1]!=flag) return;
            dfs(now-1);
            if(ok) return;
        }
        else return; 
    }
    else if(aa!=-1 && bb!=-1)
    {
        if(use[(aa+bb+bit[now])%n]) return;
        bit[now-1]=(aa+bb+bit[now])/n;
        if(flag!=2 && bit[now-1]!=flag) return;
        cc=(aa+bb+bit[now])%n;
        use[cc]=true;
        dfs(now-1);
        if(ok) return;
        use[cc]=false;
        cc=-1;
    }
    else if(aa!=-1 && cc!=-1)
    {
        if(aa+bit[now]<=cc)
        {
            if(use[cc-aa-bit[now]]) return;
            bit[now-1]=0;
            if(flag!=2 && bit[now-1]!=flag) return;
            bb=cc-aa-bit[now];
            use[bb]=true;
            dfs(now-1);
            if(ok) return;
        }
        else
        {
            if(use[cc+n-aa-bit[now]]) return;
            bit[now-1]=true;
            if(flag!=2 && bit[now-1]!=flag) return;
            bb=(cc+n-aa-bit[now])%n;
            use[bb]=true;
            dfs(now-1);
            if(ok) return; 
        }
        use[bb]=false;
        bb=-1;
    }
    else if(bb!=-1 && cc!=-1)
    {
        if(bb+bit[now]<=cc)
        {
            if(use[cc-bb-bit[now]]) return; 
            bit[now-1]=0;
            if(flag!=2 && bit[now-1]!=flag) return;
            aa=cc-bb-bit[now];
            use[aa]=true;
            dfs(now-1);
            if(ok) return;
        }
        else
        {
            if(use[cc+n-bb-bit[now]]) return;
            bit[now-1]=true;
            if(flag!=2 && bit[now-1]!=flag) return;
            aa=(cc+n-bb-bit[now])%n;
            use[aa]=true;
            dfs(now-1);
            if(ok) return;
        }
        use[aa]=false;
        aa=-1;
    }
    else if(aa!=-1)
    {
        for(int i=n-1;i>=0;i--)
        {
            if(use[i]) continue;
            if(use[(aa+i+bit[now])%n]) continue;
            bit[now-1]=(aa+i+bit[now])/n;
            if(flag!=2 && bit[now-1]!=flag) return;
            bb=i; cc=(aa+i+bit[now])%n;
            use[bb]=use[cc]=true;
            dfs(now-1);
            if(ok) return;
            use[bb]=use[cc]=false;
            bb=cc=-1;
        }
    }
    else if(bb!=-1)
    {
        for(int i=n-1;i>=0;i--)
        {
            if(use[i]) continue;
            if(use[(bb+i+bit[now])%n]) continue;
            bit[now-1]=(i+bb+bit[now])/n;
            if(flag!=2 && bit[now-1]!=flag) return;
            aa=i; cc=(bb+i+bit[now])%n;
            use[aa]=use[cc]=true;
            dfs(now-1);
            if(ok) return;
            use[aa]=use[cc]=false;
            aa=cc=-1;
        }
    }
    else if(cc!=-1)
    {
        for(int i=n-1;i>=0;i--)
        {
            if(use[i]) continue;
            if(i+bit[now]<=cc && !use[cc-i-bit[now]])
            {
                bit[now-1]=0;
                if(flag!=2 && bit[now-1]!=flag) return;
                aa=i; bb=cc-i-bit[now];
                use[aa]=use[bb]=true;
                dfs(now-1);
                if(ok) return;
                use[aa]=use[bb]=false;
                aa=bb=-1;
            }
            else if(i+bit[now]>cc && !use[cc+n-i-bit[now]])
            {     
                bit[now-1]=1;
                if(flag!=2 && bit[now-1]!=flag) return;
                aa=i; bb=(cc+n-i-bit[now])%n;
                use[aa]=use[bb]=true;
                dfs(now-1);
                if(ok) return;
                use[aa]=use[bb]=false;
                aa=bb=-1;
            }
        }
    }
    else
    {
        for(int i=n-1;i>=0;i--)
        {
            if(use[i]) continue;
            for(int j=n-1;j>=0;j--)
            {
                if((a[now]!=b[now] && i==j) || (a[now]==b[now] && i!=j) || use[j] || use[(i+j+bit[now])%n]) continue;
                bit[now-1]=(i+j+bit[now])/n;
                if(flag!=2 && bit[now-1]!=flag) return;
                aa=i; bb=j; cc=(i+j+bit[now])%n;
                use[aa]=use[bb]=use[cc]=true;
                dfs(now-1);
                if(ok) return;
                use[aa]=use[bb]=use[cc]=false;
                aa=bb=cc=-1; 
            }
        }
    }
}
int main()
{
    scanf("%d%s%s%s",&n,a,b,c);
    memset(ans,-1,sizeof(ans));
    dfs(n-1);
}

 

posted @ 2017-08-02 16:26  TRTTG  阅读(321)  评论(0编辑  收藏  举报