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

 

题目描述

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

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。

noip2004提高组第4题

 

强大的搜索。

基本思想就是枚举每个字母代表的值,并且带入计算。

把每一列当做一个整体处理,从低位往高位扫(方便计算进位)。

有一个很强的剪枝:当发现高位的某一列三个数都填上以后,如果两个加数不管进不进位都不能得到填上去的和,说明方案肯定不可行,直接剪枝。具体看代码。

 

 1 /*by SilverN*/
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 char s[30];
 9 int n;
10 int a[30],b[30],c[30];
11 int w[30];//字母对应数字
12 bool vis[30];
13 bool DFS(int p,int tmp){
14     if(!p){
15         if(tmp)return 0;
16         return 1;
17     }
18     int i,j,k;
19     for(k=p;k;--k){
20         if(w[a[k]]!=-1 && w[b[k]]!=-1 && w[c[k]]!=-1 && 
21             ( (w[a[k]]+w[b[k]])%n!=w[c[k]] && (w[a[k]]+w[b[k]]+1)%n!=w[c[k]] )  ) return 0;
22     }
23     if(w[a[p]]!=-1 && w[b[p]]!=-1){
24         int tp1=w[a[p]]+w[b[p]]+tmp;
25         if(w[c[p]]!=-1){
26             if(tp1%n!=w[c[p]])return 0;
27             else return DFS(p-1,tp1/n);
28         }
29         else{
30             int tg=tp1%n;if(vis[tg])return 0;
31             w[c[p]]=tg; vis[tg]=1;
32             if(DFS(p-1,tp1/n))return 1;
33             w[c[p]]=-1;    vis[tg]=0;
34             return 0;
35         }
36     }
37     for(register int i=n-1;i>=0;--i){//a
38         if(vis[i] && w[a[p]]!=i)continue;
39         if(w[a[p]]!=-1 && i!=w[a[p]])continue;
40         for(register int j=n-1;j>=0;--j){//b
41             if(vis[j] && w[b[p]]!=j)continue;
42             if(w[b[p]]!=-1 && j!=w[b[p]])continue;
43             k=(i+j+tmp)%n;//c
44                 if(w[c[p]]!=-1 && k!=w[c[p]])continue;
45                 if(vis[k] && w[c[p]]!=k)continue;
46                 int tp1=i+j+tmp;
47                 int cp1=w[a[p]];
48                 int cp2=w[b[p]];
49                 int cp3=w[c[p]];
50                 bool vp1=vis[i];
51                 bool vp2=vis[j];
52                 bool vp3=vis[k];
53                 w[a[p]]=i;vis[i]=1;
54                 w[b[p]]=j;vis[j]=1;
55                 w[c[p]]=k;vis[k]=1;
56                 if(DFS(p-1,tp1/n))return 1;
57                 w[a[p]]=cp1;vis[i]=vp1;
58                 w[b[p]]=cp2;vis[j]=vp2;
59                 w[c[p]]=cp3;vis[k]=vp3;
60         }
61         
62     }
63     return 0;
64 } 
65 int main(){
66     memset(w,-1,sizeof w);
67     scanf("%d",&n);
68     int i,j;
69     scanf("%s",s+1);
70     for(i=1;i<=n;i++)a[i]=s[i]-'A'+1;
71     scanf("%s",s+1);
72     for(i=1;i<=n;i++)b[i]=s[i]-'A'+1;
73     scanf("%s",s+1);
74     for(i=1;i<=n;i++)c[i]=s[i]-'A'+1;
75     DFS(n,0);
76     for(i=1;i<=n;i++)printf("%d ",w[i]);
77     return 0;
78 }

 

转载于:https://www.cnblogs.com/SilverNebula/p/5991467.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值