题目:洛谷P1092、codevs1064、Vijos P1099。
题目大意:
给你一个$n$进制、每个数都是$n$位的三个数a,b,c,这些数的数位由字母表示(共$n$个字母,从‘A’开始),所有数字都只对应一个字母,每个字母对应一个数字。
现在知道a+b=c,求每个字母代表的数字,保证有且仅有一组解。
解题思路:
暴力,从后往前搜索每一列即可。注意传递进位。
若一列知道了三个数,则判断是否合法,合法则继续搜索下一列。
若一列知道了两个数,则可以推算出第三个数,若没被使用,则继续搜索下一列。
若一列知道的数少于一个,则a或b中,一定有一个数字是不知道的。我们从大到小枚举那个数的值,然后搜**当前列**(递归)。
如果发现答案可行,则直接输出答案,退出即可。
这样搜,不用加其他剪枝,最大一个点最多800ms(其实上述分类讨论已经很好地进行了剪枝)。
C++ Code:
#include<bits/stdc++.h> int n,num[123],ur[123]; char a[123],b[132],c[213]; void dfs(int now,int jw){ if(now==-1){ for(int i=1;i<n;++i)printf("%d ",num[i+‘A‘-1]); printf("%d\n",num[n+‘A‘-1]); exit(EXIT_SUCCESS); } int i=now; //if(now!=n-1&&!check(now+1))return; if(num[a[i]]!=-1&&num[b[i]]!=-1&&num[c[i]]!=-1){ int p=num[a[i]]+num[b[i]]+jw; if(p%n==num[c[i]]){ dfs(now-1,p/n); } return; } if(num[a[i]]!=-1&&num[b[i]]!=-1){ int p=num[a[i]]+num[b[i]]+jw; if(!ur[p%n]){ ur[p%n]=1; num[c[i]]=p%n; dfs(now-1,p/n); num[c[i]]=-1; ur[p%n]=0; } return; } if(num[a[i]]!=-1&&num[c[i]]!=-1){ int p=num[c[i]]-jw-num[a[i]]+n; if(!ur[p%n]){ ur[p%n]=1; num[b[i]]=p%n; dfs(now-1,!(p/n)); num[b[i]]=-1; ur[p%n]=0; } return; } if(num[b[i]]!=-1&&num[c[i]]!=-1){ int p=num[c[i]]-jw-num[b[i]]+n; if(!ur[p%n]){ ur[p%n]=1; num[a[i]]=p%n; dfs(now-1,!(p/n)); num[a[i]]=-1; ur[p%n]=0; } return; } if(num[a[i]]!=-1){ for(int j=n-1;j>-1;--j) if(!ur[j]){ ur[j]=1; num[b[i]]=j; dfs(now,jw); num[b[i]]=-1; ur[j]=0; } }else{ for(int j=n-1;j>-1;--j) if(!ur[j]){ ur[j]=1; num[a[i]]=j; dfs(now,jw); num[a[i]]=-1; ur[j]=0; } } } int main(){ scanf("%d%s%s%s",&n,a,b,c); memset(ur,0,sizeof ur); memset(num,-1,sizeof num); dfs(n-1,0); return EXIT_FAILURE; }
原文地址:https://www.cnblogs.com/Mrsrz/p/9026478.html
时间: 2024-11-02 17:21:34