[题解]洛谷P1092 虫食算

  P1092

  我太弱了,竟然打了一个上午。。。。。。

  一开始我竟然想从A到B枚举每一种排列最后检查。。。很显然这种方法效率特别低——O(N!)

  于是想到了由低位到高位,由两个加数上的位到和上的位,逐个枚举数字。当然如果不剪枝的话就和第一种方法没什么区别

  

  剪枝一:

  这个剪枝比较好想,在每枚举完一列时(或者该列上的数字已被枚举了),检查上两行(加数位)之和加上上一位的进位对进制数取模是否等于最后一行(两数之和的位),如果不相等就说明当前状态无法得出正解,可以剪枝。

  剪枝二:

  这个有点难想到。

  众所周知,加法中进位最多为1(小学数学知识)

  那么对于每一位,如果该位上的三个数都被枚举过了,记第一行数为a,第二行为b,第三行为c,则可以分以下两种情况讨论:

  1. 上一位无进位,则a+b==c
  2. 上一位有进位,则a+b+1==c

  如果对于以上两种情况均不成立,则说明当前状态无法得出正解,可以剪枝。

   (如果有不理解的可以问我或者结合代码注释理解)

  上代码:

  

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;

int n,ans[30],use[30]={0};
char s[4][30];

//给每一个编号 
int id(char ch){
    return ch-'A'+1;
}

//输出结果 
void print(){
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
}

void dfs(int x,int y,int z){
    if(x==0&&z==0){
        print();
        exit(0);//找到答案直接滚粗 
    }
    else{
        
        //剪枝二 
        /*那么对于每一位,如果该位上的三个数都被枚举过了,记第一行数为a,第二行为b,第三行为c,则可以分以下两种情况讨论:
        上一位无进位,则a+b==c
        上一位有进位,则a+b+1==c*/
        int a,b,c;
        for(int i=x-1;i>0;i--){
            a=ans[id(s[1][i])];b=ans[id(s[2][i])];c=ans[id(s[3][i])];
            if(a!=-1&&b!=-1&&c!=-1&&(a+b)%n!=c&&(a+b+1)%n!=c)
                return;
        }
        
        if(ans[id(s[y][x])]==-1){
            //前两行 
            if(y<3){
                for(int i=0;i<n;i++){
                    if(!use[i]){
                        ans[id(s[y][x])]=i;use[i]=1;
                        dfs(x,y+1,z);
                        ans[id(s[y][x])]=-1;use[i]=0;
                    }
                }
            }
            //第三行 
            if(y==3){
                for(int i=0;i<n;i++){
                    if(!use[i]){
                        int zz=ans[id(s[1][x])]+ans[id(s[2][x])]+z;
                        //剪枝一 
                        if(zz%n==i){     
                            ans[id(s[y][x])]=i;use[i]=1;
                            dfs(x-1,1,zz/n);
                            ans[id(s[y][x])]=-1;use[i]=0;
                        }
                    }
                }
            }
        }
        else{
            //前两行 
            if(y<3){
                dfs(x,y+1,z);
            }
            //第三行 
            if(y==3){
                int zz=ans[id(s[1][x])]+ans[id(s[2][x])]+z;
                //剪枝一 
                if(zz%n==ans[id(s[3][x])]){   
                    dfs(x-1,1,zz/n);
                }
            }
        }
    }
} 

int main(){
    memset(ans,-1,sizeof(ans));//初始化为-1,因为每一个数也可以是0 
    scanf("%d",&n);
    scanf("%s%s%s",s[1]+1,s[2]+1,s[3]+1);
    dfs(n,1,0);//从最低位的第一个加数开始枚举 
    return 0;
} 

  施工Van♂毕!ヾ(゚∀゚ゞ)~~~~~~~

猜你喜欢

转载自www.cnblogs.com/sjrb/p/10293129.html