P1092虫食算题解

2018-10-24

题目链接

题目思路:

我就讲下剪枝操作吧。

三个式子从上到下为A,B,C

剪枝操作

1.从3个式子右边开始从上到下枚举字母对应数字。(搜索顺序关键)

2.末尾(A+B)%n!=C。

3.已知A,B,不知C,且C的可能数字已经使用。(这三个点从2000ms)

4.已知A.C,不知B,且B的可能数字已经使用。(一下剪枝成)

5.已知B,C,不知A,且A的可能数字已经使用。(100ms)

6.已知A,B,C,且A+B不等于C,且A+B+1不等于C。

7.已经A,B,C的最高位,且A+B有进位

8.逆序枚举数字。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<map>
#define R register
using namespace std;
const int N=30;
int n,dis[N],flag[N],num,mp2[N];
char a[N],b[N],c[N],mp1[N];
inline int read(){
 R int s=0,w=1;R char ch=getchar();
 while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)w=-1;ch=getchar();}
 while(ch>=‘0‘&&ch<=‘9‘) s=s*10+ch-‘0‘,ch=getchar();
 return s*w;
}
inline void write(R int x) {
    if(x < 0) {
        putchar(‘-‘);
        x = -x;
    }
    if(x >= 10) write(x / 10);
    putchar(x % 10 + ‘0‘);
}
inline int judge(){
        R int cnt=0;
        R int q=0,e=0,x=0;
        R int ss[N];
        for(R int i=n-1;i>=0;--i){
              ++cnt;
              ss[n-i-1]=x+dis[mp2[a[i]&31]]+dis[mp2[b[i]&31]];
              x=ss[n-i-1]/n;
              ss[n-i-1]%=n;
        }
        if(x)return 0;
        for(R int i=0;i<=n-1;++i)q=(q<<1)*5+ss[i];
        for(R int i=0;i<=n-1;++i)e=(e<<1)*5+dis[mp2[c[n-i-1]&31]];
        if(e==q)return 1;
        return 0;
}
inline int jianzhi(){
      if(dis[mp2[a[n-1]&31]]!=-1&&dis[mp2[b[n-1]&31]]!=-1&&dis[mp2[c[n-1]&31]]!=-1&&(dis[mp2[a[n-1]&31]]+dis[mp2[b[n-1]&31]])%n!=dis[mp2[c[n-1]&31]])return 1;
      if((dis[mp2[a[0]&31]]!=-1)&&(dis[mp2[b[0]&31]]!=-1)&&(dis[mp2[a[0]&31]]+dis[mp2[b[0]&31]]>=n))return 1;
        for(R int i=n-1;i>=0;--i){
                if((dis[mp2[a[i]&31]]!=-1)&&(dis[mp2[b[i]&31]]!=-1)&&(dis[mp2[c[i]&31]]==-1)&&(flag[(dis[mp2[a[i]&31]]+dis[mp2[b[i]&31]])%n]==1&&flag[(dis[mp2[a[i]&31]]+dis[mp2[b[i]&31]]+1)%n]==1))return 1;
           if((dis[mp2[a[i]&31]]!=-1)&&((dis[mp2[c[i]&31]]!=-1))&&(dis[mp2[b[i]&31]]==-1)&&flag[(dis[mp2[c[i]&31]]-dis[mp2[a[i]&31]]+n)%n]&&flag[(dis[mp2[c[i]&31]]-dis[mp2[a[i]&31]]-1+n)%n])return 1;
           if((dis[mp2[b[i]&31]]!=-1)&&((dis[mp2[c[i]&31]]!=-1))&&(dis[mp2[a[i]&31]]==-1)&&(flag[(dis[mp2[c[i]&31]]-dis[mp2[b[i]&31]]+n)%n])&&(flag[(dis[mp2[c[i]&31]]-dis[mp2[b[i]&31]]-1+n)%n]))return 1;
        if(dis[mp2[a[i]&31]]!=-1&&dis[mp2[b[i]&31]]!=-1&&dis[mp2[c[i]&31]]!=-1){
if((((dis[mp2[a[i]&31]]+dis[mp2[b[i]&31]])%n)!=dis[mp2[c[i]&31]])&&(((dis[mp2[a[i]&31]]+dis[mp2[b[i]&31]]+1)%n)!=dis[mp2[c[i]&31]]))return 1;
        }
        }
        return 0;
}
void dfs(R int pos){
        if(jianzhi())return;
        if(pos==n+1){
            if(judge()){
            for(R int i=‘A‘;i<=‘A‘+n-1;++i){
            write(dis[mp2[i&31]]);
            printf(" ");
            }
            exit(0);
            }
            return;
        }
        for(R int i=n-1;i>=0;--i){
            if(!flag[i]){
            dis[pos]=i;flag[i]=1;
            dfs(pos+1);
            dis[pos]=-1;flag[i]=0;
            }
        }
}
int main(){
      memset(dis,-1,sizeof(dis));
        n=read();scanf("%s",a);
        scanf("%s",b);scanf("%s",c);
        for(R int i=n-1;i>=0;--i){
              if(mp2[a[i]&31]==0){
                ++num;
                mp2[(a[i]&31)]=num;
                mp1[num]=a[i];
            }
                  if(mp2[c[i]&31]==0){
                  ++num;
                mp2[(c[i]&31)]=num;
                mp1[num]=c[i];
            }
                  if(mp2[b[i]&31]==0){
                ++num;
                mp2[(b[i]&31)]=num;
                mp1[num]=b[i];
            }
        }
        for(R int i=n-1;i>=0;--i){
        dis[1]=i;flag[i]=1;
        dfs(2);
        dis[1]=-1;flag[i]=0;
        }
        return 0;
}

原文地址:https://www.cnblogs.com/sky-zxz/p/9841117.html

时间: 2024-10-10 05:04:33

P1092虫食算题解的相关文章

P1092 虫食算——题解

题目传送 (据说官方正解为高斯消元,但用搜索也能过,这里就讲讲搜索算法吧.) 对于一道搜索题,首先考虑一下大体怎样搜索.因为要考虑加法的进位,所以从左往右搜索对于考虑进位来说十分麻烦,而从右往左搜索就没有这种麻烦,故搜索顺序从右往左.但是发现整个式子的一位上由三个字符串的一位组成,且这三个分别担当加数.结果中的一部分,逐个搜索的话还要麻烦地分类讨论,考虑再优化一下搜索顺序.发现一共只有n个不同的数和字母,并且每个数和字母都至少出现一次,那么可以从右往左找出字母第一次出现的位置并存到next数组里

洛谷 P1092 虫食算

P1092 虫食算 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: http://paste.ubuntu.com/25448822/ 其中#号代表被虫子啃掉的数字.根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5. 现在,我们对问题做两个限制: 首先,我们只考虑加法的虫食算.这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0. 其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,

Luogu P1092 虫食算(枚举+剪枝)

P1092 虫食算 题面 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 + 8468#6633 44445509678 其中 \(\#\) 号代表被虫子啃掉的数字.根据算式,我们很容易判断:第一行的两个数字分别是 \(5\) 和 \(3\) ,第二行的数字是 \(5\) . 现在,我们对问题做两个限制: 首先,我们只考虑加法的虫食算.这里的加法是 \(N\) 进制加法,算式中三个数都有 \(N\

[NOIP2004] 提高组 洛谷P1092 虫食算

题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 其中#号代表被虫子啃掉的数字.根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5. 现在,我们对问题做两个限制: 首先,我们只考虑加法的虫食算.这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0. 其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用

洛谷—— P1092 虫食算

https://www.luogu.org/problem/show?pid=1092 题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: http://paste.ubuntu.com/25448822/ 其中#号代表被虫子啃掉的数字.根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5. 现在,我们对问题做两个限制: 首先,我们只考虑加法的虫食算.这里的加法是N进制加法,算式中三个数都有N位,允许有前

洛谷 P1092 虫食算 Label:dfs

题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 其中#号代表被虫子啃掉的数字.根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5. 现在,我们对问题做两个限制: 首先,我们只考虑加法的虫食算.这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0. 其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用

Luogu P1092 虫食算

题目描述 所谓虫食算,就是原先的算式中有一部分被虫子啃掉了,需要我们根据剩下的数字来判定被啃掉的字母.来看一个简单的例子: 43#9865#045 +8468#6633 44445509678 其中#号代表被虫子啃掉的数字.根据算式,我们很容易判断:第一行的两个数字分别是5和3,第二行的数字是5. 现在,我们对问题做两个限制: 首先,我们只考虑加法的虫食算.这里的加法是N进制加法,算式中三个数都有N位,允许有前导的0. 其次,虫子把所有的数都啃光了,我们只知道哪些数字是相同的,我们将相同的数字用

洛谷P1092虫食算——深搜

题目:https://www.luogu.org/problemnew/show/P1092 剪枝1:从右往左.从上往下按字母出现顺序搜索: 剪枝2:同一列前两个数字确定,可直接算出第三个数字并判断: 剪枝3:每次搜索前看看前面的列上有没有已经不符合的情况(进位最多为1): 代码如下: #include<iostream> #include<cstdio> using namespace std; int n,c[300],jin[30]; char a[5][30]; bool

LUGOU P1092 虫食算

传送门 解题思路 刚开始按yzy神犇给的方法写,就是每次要把能算出来的都算出来,结果因为太菜写挂了..后来直接爆搜水过.. #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> using namespace std; const int MAXN=40; int n,a[MAXN],cnt; char s[4][MAXN];