zoukankan      html  css  js  c++  java
  • 【搜索】$P1092$虫食算

    题目链接

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

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

    输入格式

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

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

    输出格式

    一行,即唯一的那组解。

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

    对于30%的数据,保证有(N leq 10)

    对于50%的数据,保证有(N leq 15)

    对于全部的数据,保证有(N leq 26)

    Solution

    搜索是比较好想的。但若直接枚举全排列需要n!,那么需要剪枝。

    考虑加法,进位的话只会进1,所以如果(A + B) % n != C && (A + B +1) % n != C,显然不合法。然后因为三个数都是N位,所以最高位不可能进位。

    那么什么搜索顺序会更优呢?从右往左,也就是从低位到高位。从右往左,按照字母出现顺序搜索,能在很大程度上提高剪枝效率。

    最后,最关键的一点,是一个exit(0)的应用。第一次知道这到底是个什么。

    exit(0):正常运行程序并退出程序。 exit 是一个函数。 exit是系统调用级别的,它表示了一个进程的结束。 exit是进程的退出。 exit是操作系统提供的(或者函数库中给出的)。 exit函数是退出应用程序,删除进程使用的内存空间,并将应用程序的一个状态返回给OS,这个状态标识了应用程序的一些运行信息,这个信息和机器和操作系统有关,一般是 0 为正常退出,非0 为非正常退出。 6. 非主函数中调用return和exit效果很明显,但是在main函数中调用return和exit的现象就很模糊,多数情况下现象都是一致的。

    #include <algorithm>
    #include <iostream>
    #include <cstdio>
    using namespace std;
    long long read(){
      long long x = 0; int f = 0; char c = getchar();
      while(c < '0' || c > '9') f |= c == '-', c = getchar();
      while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
      return f? -x:x;
    }
    
    int a[30], b[30], c[30], num[30], qu[30], n, cnt;
    char s1[30], s2[30], s3[30];
    bool used[30];
    bool ok(){//最后判断一下是否满足等式
        for(int i = n - 1, x = 0; i >= 0; --i){
            int A = num[a[i]], B = num[b[i]], C = num[c[i]];
            if((A + B + x) % n != C) return 0;
            x = (A + B + x) / n;
        }
        return 1;
    }
    void print(){//输出
        printf("%d", num[0]);
        for(int i = 1; i < n; ++i) printf(" %d", num[i]);
        exit(0);//减少递归返回时间
    }
    void dfs(int x){
        if(num[a[0]] + num[b[0]] >= n) return;//最高位没有进位
        for(int i = n - 1; i >= 0; --i){
            int A = num[a[i]], B = num[b[i]], C = num[c[i]];
            if(A == -1 || B == -1 || C == -1) continue;
            if((A + B) % n != C && (A + B + 1) % n != C) return;//判每一位是否合法
        }
        if(x == n){
            if(ok()) print();
            return;
        }
        for(int i = n - 1; i >= 0; --i)
            if(!used[i]){
                num[qu[x]] = i, used[i] = 1;
                dfs(x + 1);
                num[qu[x]] = -1, used[i] = 0;//回溯
            }
    }
    void Sort(int x){//预处理递归枚举顺序
        if(!used[x]) used[x] = 1, qu[cnt++] = x;
    }
    int main(){
    	freopen("1.txt", "r", stdin);
    	freopen("1.out", "w", stdout);
        n = read();
        scanf("%s%s%s", s1, s2, s3);
        for(int i = 0; i < n; ++i)
            a[i] = s1[i] - 'A', b[i] = s2[i] - 'A', c[i] = s3[i] - 'A', num[i] = -1;
        for(int i = n - 1; i >= 0; --i){
            Sort(a[i]);//预处理顺序
            Sort(b[i]);
            Sort(c[i]);
        }
        for(int i = 0; i < n; ++i) used[i] = 0;
        dfs(0);
        return 0;
    }
    
  • 相关阅读:
    用Live Writers发布Blog
    ScribeFire
    再再上传一个图片
    jQuery页面加载初始化常用的三种方法
    JS 20200101T00:00:00.000000Z 日期格式转换、Sun Jul 04 2021 00:00:00 GMT+0800 (中国标准时间)转20210704 00:00
    vue 组件传值 props $emit $event
    jquery或js如何判断一个层是显示还是隐藏
    js合并俩个数组的三种方法
    uniapp生命周期
    SVN版本冲突
  • 原文地址:https://www.cnblogs.com/kylinbalck/p/11307087.html
Copyright © 2011-2022 走看看