【ybtoj】【DFS】【例题3】虫食算

【例题3】虫食算


link

传送门
题目


解题思路

40分:暴力搜索每个字母代表的数

考虑剪枝 (搜索字母的顺序按竖式的从右到左,方便剪枝)
每搜索一个字母时,其实已经可以判断竖式的可行性了

  1. 当竖式上当前位的右边都时, ( x + y ) % n < > z (x+y)\%n<>z (x+y)%n<>z不可行(加数 x , y x,y x,y,和 z z z)。
    但是还要考虑进位,设右边进位 t t t ( x + y + t ) % n < > z (x+y+t)\%n<>z (x+y+t)%n<>z不可行
  2. 当竖式上当前位的右边有字母没有搜索时,无法判断有没有进位
    但是加法中的进位最多为1,即当 ( x + y ) % n < > z (x+y)\%n<>z (x+y)%n<>z ( x + y + 1 ) % n < > z (x+y+1)\%n<>z (x+y+1)%n<>z不可行
  3. 当前位已是第一位,但是依然有进位, ( i = = 1 ) (i ==1) (i==1) ( x + y ) / n > 0 (x+y)/n>0 (x+y)/n>0不可行

Code

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>

using namespace std;

string s[5];
int n, ans[30], v[30], q[30], num, h;

bool check() {
    
    //判断可行性
	int t = 0;
	for (int i = n; i; i--) {
    
    
		int x = ans[s[1][i - 1] - 'A' + 1], y = ans[s[2][i - 1] - 'A' + 1], z = ans[s[3][i - 1] - 'A' + 1];
		if (x != -1 && y != -1 && z != -1) {
    
    
			if (t != -1) {
    
    
				if ((x + y + t) % n != z) return 0;//1
				if (i == 1 && (x + y + t) / n) return 0;//3
				t = (x + y + t) / n;
			}else {
    
    
				if ((x + y) % n != z && (x + y + 1) % n != z) return 0;//2
				if (i == 1 && (x + y) / n) return 0;//3
			}
		}else t = -1;//当前位有字母还没搜索,进位设为-1
	}
	return 1;
}

void dfs(int x) {
    
    
	if (h) return;//已经找到答案就直接返回
	if (x > n) {
    
    //找到答案
		for (int i = 1; i <= n; i++)
			printf ("%d ", ans[i]);
		h = 1;
		return;
	}
	for (int i = 0; i < n; i++) {
    
    
		if (!v[i]) {
    
    //搜索每个字母可用数字
			v[i] = 1, ans[q[x]] = i;
			if (check())
				dfs(x + 1);
			v[i] = 0, ans[q[x]] = -1;
		}
	}
}

int main() {
    
    
	scanf("%d", &n);
	cin>>s[1]>>s[2]>>s[3];
	for (int i = n - 1; i >= 0; i--) //从有到左
		for (int j = 1; j <= 3; j++) //从上到下(这个不太重要)
			if (!v[s[j][i] - 'A' + 1]) {
    
    
				v[s[j][i] - 'A' + 1] = 1;
				q[++num] = s[j][i] - 'A' + 1;//字母按出现顺序记录
			}
	memset (v, 0, sizeof(v));
	memset (ans, -1, sizeof(ans));
	dfs(1);
}

猜你喜欢

转载自blog.csdn.net/qq_39940018/article/details/112135092