【NOIP2004】虫食算(搜索+高斯消元)

    xiaoxiao2021-03-26  24

    题意:给定一个n进制的竖式计算(n位数+n位数=n位数),相同字母表示相同的数,不同字母表示不同的数(填数游戏),保证有且仅有唯一解。

    做法1:暴力虫食算暴力

    做法2:搜索+高斯消元 每一位列一个方程,添加n个未知数,表示每一位的进位状况。 列方程:每一位:两个加数系数为1,和系数为-1,当前这一位系数-n,前一位系数1。 然后跑一遍高斯(肯定是解不出来的,未知数>方程数),然后dfs枚举进位的状态,算出未知数,检验是否合法。

    代码:

    #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> using std::swap; #define MAXN 30 int N,finalR,ans[MAXN]; char eq[3][MAXN]; int A[MAXN][MAXN*2]; bool car[MAXN],vis[MAXN]; int gcd(int a,int b){return b==0?a:gcd(b,a%b);} int lcm(int a,int b){return a/gcd(a,b)*b;} inline void Init_Matrix() { memset(A,0,sizeof A); for(int i=N-1;i>=0;i--) { A[i+1][eq[0][i]-'A'+1]++; A[i+1][eq[1][i]-'A'+1]++; A[i+1][eq[2][i]-'A'+1]--; A[i+1][N+i+1]=-N; A[i+1][N+i+2]=1; A[i+1][N*2+1]=0; } } inline void Gauss() { int r,c,mxr,n=N,m=N*2+1,l,ta,tb; for(r=1,c=1;r<=n&&c<m;r++,c++) { mxr=r; for(int i=r+1;i<=n;i++) if(abs(A[i][c])>abs(A[mxr][c])) mxr=i; if(A[mxr][c]==0) {r--;continue;} if(mxr!=r)swap(A[mxr],A[r]); for(int i=1;i<=n;i++) if(i!=r&&A[i][c]) { l=lcm(abs(A[i][c]),abs(A[r][c])); ta=l/A[i][c]; tb=l/A[r][c]; for(int j=c;j<=m;j++) A[i][j]=A[i][j]*ta-A[r][j]*tb; if(i<c) A[i][i]*=ta; } } finalR=r-1; } inline bool Check() { memset(vis,0,sizeof vis); memset(ans,0,sizeof ans); int sum; for(int i=N;i>0;i--) { sum=A[i][N*2+1]; for(int j=N+1;j<=N*2;j++) sum-=A[i][j]*car[j-N]; if(sum%A[i][i])return 0; ans[i]=sum/A[i][i]; if(ans[i]<0||ans[i]>=N||vis[ans[i]])return 0; vis[ans[i]]=1; } for(int i=1;i<N;i++) printf("%d ",ans[i]); printf("%d\n",ans[N]); return 1; } void Enum_carry(int id) { if(id>N) { if(Check()) exit(0); return; } car[id]=0; Enum_carry(id+1); car[id]=1; Enum_carry(id+1); } int main() { scanf("%d%s%s%s",&N,eq[0],eq[1],eq[2]); Init_Matrix(); Gauss(); Enum_carry(2); printf("Error\n"); return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-661793.html

    最新回复(0)