虫食算

版权声明: https://blog.csdn.net/qq_38234381/article/details/82320193

题目链接:https://www.luogu.org/problemnew/show/P1092

正解是高斯消元,但搜索也勉强可以过。

首先一个很明显的思路就是竖着搜的策略,一旦发现不合法的情况,就return。但这样最多也只能得80分,因此需要剪枝,可以在每次搜索之前从当前位置到0进行一次判断,若有不合法的情况,就返回false,具体可以看代码。

code:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

const int N=30;
int n, ans[N], cn[N], nc[N];
string s1, s2, s3;
bool finds;

bool check(int pos) {
	int i, temp1, temp2, temp3, k;
	for (i=pos; i>=0; i--) {
		temp1=cn[s1[i]-'A'+1], temp2=cn[s2[i]-'A'+1], temp3=cn[s3[i]-'A'+1];
		if (temp1==-1 || temp2==-1 || temp3==-1) continue;
		if (temp1+temp2>=n-1) k=temp1+temp2-n;
		else k=temp1+temp2;
		if (k>temp3) return false;
		if (k+1<temp3) return false;
	}
	return true;
}

void dfs(int pos, int last) {
	int i, j, k;
	if (!check(pos)) return ;
	if (pos == -1) {
		finds=true;
		return ;
	}
	if (cn[s1[pos]-'A'+1]<0 && cn[s2[pos]-'A'+1]<0) {
		if (s1[pos]!=s2[pos]) {
			for (i=0; i<n; i++) {
				if (nc[i]) continue;
				for(j=0; j<n; j++) {
					if (nc[j]) continue;
					if (i==j) continue;
					bool flag=false;
					int carry=0;
					cn[s1[pos]-'A'+1]=i, cn[s2[pos]-'A'+1]=j;
					if (i+j+last>=n) {
						k=i+j+last-n;
						carry=1;
					}
					else k=i+j+last;
					if (cn[s3[pos]-'A'+1]<0) {
						flag=true;
						cn[s3[pos]-'A'+1]=k;
					}
					else if (cn[s3[pos]-'A'+1]!=k) {
						cn[s1[pos]-'A'+1]=-1, cn[s2[pos]-'A'+1]=-1;
						continue;
					} 
					nc[i]=s1[pos]-'A'+1, nc[j]=s2[pos]-'A'+1;
					dfs(pos-1, carry);
					if (finds) return ;
					cn[s1[pos]-'A'+1]=-1, cn[s2[pos]-'A'+1]=-1;
					nc[i]=0, nc[j]=0;
					if (flag) cn[s3[pos]-'A'+1]=-1;
				}
			}
		}
		else {
			for (i=0; i<n; i++) {
				if (nc[i]) continue;
				int carry=0;
				bool flag=false;
				cn[s1[pos]-'A'+1]=i, j=i;
				if (i+j+last>=n) {
					k=i+j+last-n;
					carry=1;
				}
				else k=i+j+last;
				if (cn[s3[pos]-'A'+1]<0) {
					flag=true;
					cn[s3[pos]-'A'+1]=k;
				}
				else if (cn[s3[pos]-'A'+1]!=k) {
					cn[s1[pos]-'A'+1]=-1;
					continue;
				}
				nc[i]=s1[pos]-'A'+1;
				dfs(pos-1,carry);
				if (finds) return ;
				cn[s1[pos]-'A'+1]=-1, nc[i]=0;
				if (flag) cn[s3[pos]-'A'+1]=-1;
			}
		}
	}
	else {
		if (cn[s1[pos]-'A'+1]<0 && cn[s2[pos]-'A'+1]>=0) {
			for (i=0; i<n; i++) {
				if (nc[i]) continue;
				int carry=0;
				bool flag=false;
				cn[s1[pos]-'A'+1]=i, j=cn[s2[pos]-'A'+1];
				if(i+j+last>=n) {
					k=i+j+last-n;
					carry=1;
				}
				else k=i+j+last;
				if (cn[s3[pos]-'A'+1]<0) {
					flag=true;
					cn[s3[pos]-'A'+1]=k;
				}
				else if (cn[s3[pos]-'A'+1]!=k) {
					cn[s1[pos]-'A'+1]=-1;
					continue;
				}
				nc[i]=s1[pos]-'A'+1;
				dfs(pos-1, carry);
				if (finds) return ;
				cn[s1[pos]-'A'+1]=-1, nc[i]=0;
				if (flag) cn[s3[pos]-'A'+1]=-1;
			}
		}
		if (cn[s1[pos]-'A'+1]>=0 && cn[s2[pos]-'A'+1]<0) {
			for (i=0; i<n; i++) {
				if (nc[i]) continue;
				int carry=0;
				bool flag=false;
				cn[s2[pos]-'A'+1]=i, j=cn[s1[pos]-'A'+1];
				if(i+j+last>=n) {
					k=i+j+last-n;
					carry=1;
				}
				else k=i+j+last;
				if (cn[s3[pos]-'A'+1]<0) {
					flag=true;
					cn[s3[pos]-'A'+1]=k;
				}
				else if (cn[s3[pos]-'A'+1]!=k) {
					cn[s2[pos]-'A'+1]=-1;
					continue;
				}
				nc[i]=s2[pos]-'A'+1;
				dfs(pos-1, carry);
				if (finds) return ;
				cn[s2[pos]-'A'+1]=-1, nc[i]=0;
				if (flag) cn[s3[pos]-'A'+1]=-1;
			}
		}
		if (cn[s1[pos]-'A'+1]>=0 && cn[s2[pos]-'A'+1]>=0) {
			int carry=0;
			bool flag=false;
			i=cn[s1[pos]-'A'+1], j=cn[s2[pos]-'A'+1];
			if (i+j+last>=n) {
				k=i+j+last-n;
				carry=1;
			}
			else k=i+j+last;
			if (cn[s3[pos]-'A'+1]<0) {
				flag=true;
				cn[s3[pos]-'A'+1]=k;
			}
			else if (cn[s3[pos]-'A'+1]!=k) return ;
			dfs(pos-1, carry);
			if (finds) return ;
			if (flag) cn[s3[pos]-'A'+1]=-1;
		}
	}
	return ;
}

int main() {
	memset(cn, -1, sizeof(cn));
	int i;
	cin >> n;
	cin >> s1 >> s2 >> s3;
	dfs(n-1, 0);
	for (i=1; i<=n; i++)
		cout << cn[i] <<" ";
	return 0;
}

如果不开O2的话只能得90分,剪枝和搜索的过程都比较玄学。

猜你喜欢

转载自blog.csdn.net/qq_38234381/article/details/82320193