zoukankan      html  css  js  c++  java
  • P1092 虫食算——题解

    题目传送

    (据说官方正解为高斯消元,但用搜索也能过,这里就讲讲搜索算法吧。)

      对于一道搜索题,首先考虑一下大体怎样搜索。因为要考虑加法的进位,所以从左往右搜索对于考虑进位来说十分麻烦,而从右往左搜索就没有这种麻烦,故搜索顺序从右往左。但是发现整个式子的一位上由三个字符串的一位组成,且这三个分别担当加数、结果中的一部分,逐个搜索的话还要麻烦地分类讨论,考虑再优化一下搜索顺序。发现一共只有n个不同的数和字母,并且每个数和字母都至少出现一次,那么可以从右往左找出字母第一次出现的位置并存到next数组里,只要按照next数组搜一遍就完事了。

      显然一个裸搜在此题肯定会TLE了,考虑一下剪枝。由于每个字符串都有n位,那么作为加数的两个字符串的最高位加进位加起来一定不能大于等于n导致进位。同时如果发现在同一位的数若都已经确定,发现两加数那一位上的数的和mod n(不进位的情况)不等于结果那一位上的数,并且两加数那一位上的数的和+1再mod n(进位的情况)仍然不等于结果那一位上的数,显然是不合题意的,故要剪掉。

      一个小技巧:发现相同的字母代表相同的数。我们可以把字母数字化,即每个字母都减'A'加1,这样若原字母为'A',处理后就为1,若为'B',就为2,...以此类推。这样可以让处理后的值作为最后记录答案的数组num的下标,同一个字母处理后的变为的下标也一样,故可以统一处理。

    见AC代码:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cstdlib>
      5 
      6 using namespace std;
      7 
      8 int n;
      9 
     10 char s1[28],s2[28],s3[28];
     11 
     12 int a[28],b[28],c[28],next[28],cnt,num[28];
     13 
     14 bool used[28];
     15 
     16 inline void getused(int x)//处理出next数组 
     17 {
     18     if(!used[x])
     19     {
     20         used[x]=1;
     21         next[++cnt]=x;
     22     }
     23 }
     24 
     25 inline int canprune()//剪枝判断  prune:剪枝(来自翻译) 
     26 {
     27     if(num[a[1]]+num[b[1]]>=n)
     28         return 1;
     29     int A,B,C;
     30     for(int i=n;i>=1;i--)
     31     {
     32         A=num[a[i]],B=num[b[i]],C=num[c[i]];
     33         if(A==-1||B==-1||C==-1) continue;
     34         if((A+B)%n!=C&&(A+B+1)%n!=C) return 1;
     35     }
     36     return 0;
     37 }
     38 
     39 inline int judge()//结果判断 
     40 {
     41     if(num[a[1]]+num[b[1]]>=n)
     42         return 0;
     43     int A,B,C,x=0;
     44     for(int i=n;i>=1;i--)
     45     {
     46         A=num[a[i]],B=num[b[i]],C=num[c[i]];
     47         if((A+B+x)%n!=C) return 0;
     48         x=(A+B+x)/n;
     49     }
     50     return 1;
     51 }
     52 
     53 void print()
     54 {
     55     for(int i=1;i<n;i++)
     56         printf("%d ",num[i]);
     57     cout<<num[n];
     58     exit(0);//要用 stdlib.h 或 cstdlib库(少了头文件的话本地虽然能过,但交上去就回CE),作用是直接退出程序。 
     59 }
     60 
     61 void dfs(int k)
     62 {
     63     for(int i=n-1;i>=0;--i)
     64     if(!used[i])
     65     {
     66         num[next[k]]=i;
     67         used[i]=1;
     68         if(k==n)
     69         {
     70             if(judge())
     71                 print();
     72         }
     73         else
     74         {
     75             if(!canprune())
     76                 dfs(k+1);
     77         }
     78         num[next[k]]=-1;
     79         used[i]=0;
     80     }
     81 }
     82 
     83 int main()
     84 {
     85     scanf("%d",&n);
     86     scanf("%s%s%s",s1,s2,s3);
     87     for(int i=n;i>=1;--i)
     88     {
     89         a[i]=s1[i-1]-'A'+1;
     90         getused(a[i]);
     91         b[i]=s2[i-1]-'A'+1;
     92         getused(b[i]);
     93         c[i]=s3[i-1]-'A'+1;
     94         getused(c[i]);
     95     }
     96     memset(num,-1,sizeof num);
     97     memset(used,0,sizeof used);
     98     dfs(1);
     99     return 0;
    100 }
  • 相关阅读:
    nyoj 199 无线网络覆盖
    hdoj 2682 Tree
    nyoj 845 无主之地1
    hdoj 1874 畅通工程续【dijkstra算法or spfa算法】
    hdoj 2544 最短路【dijkstra or spfa】
    hdoj 4548 美素数
    打表法
    hdoj 2098 分拆素数和
    hdoj 1262 寻找素数对
    bzoj1180,2843
  • 原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/11181367.html
Copyright © 2011-2022 走看看