虫食算【DFS】

>Link

ybtoj虫食算


>解题思路

30分做法:暴搜每个字母所代表的数字,然后判断是否合法

正解
我们可以考虑如下剪枝:
模拟加法的过程,记录当前位的加数 j 1 j1 j1 j 2 j2 j2和和 p p p

  1. 如果当前位右边所有的数都确定了,那么也就可以确定进位为 g g g,如果 j 1 + j 2 + g ≠ p j1+j2+g≠p j1+j2+g=p的话,舍去
  2. 如果当前位右边有数没有确定的话,那么当前进位 g g g可能为1或者0,如果 j 1 + j 2 j1+j2 j1+j2 j 1 + j 2 + 1 j1+j2+1 j1+j2+1 ≠ p ≠p =p,也说明不合法
  3. 最后检查一下位数是否会大于 n n n

应用这个思想,我们搜索的时候也应该按照从右到左最先出现的字母开始搜


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n, w[30], q[30];
string s[5];
bool u[30], mark[30];

bool check ()
{
    
    
	int g = 0, j1, j2, p;
	for (int i = n; i >= 1; i--)
	{
    
    
		j1 = w[s[1][i - 1] - 'A' + 1];
		j2 = w[s[2][i - 1] - 'A' + 1];
		p = w[s[3][i - 1] - 'A' + 1];
		if (j1 != -1 && j2 != -1 && p != -1)
		{
    
    
			if (g != -1)
			{
    
    
				if ((j1 + j2 + g) % n != p) return 0;
				g = (j1 + j2 + g) / n;
			}
			else
			{
    
    
				if ((j1 + j2) % n != p && (j1 + j2 + 1) % n != p) return 0;
				if (i == 1 && j1 + j2 >= n) return 0;
			}
		}
		else g = -1;
	}
	if (g > 0) return 0;
	return 1;
}
void dfs (int now)
{
    
    
	if (now == n + 1)
	{
    
    
		for (int i = 1; i <= n; i++) printf ("%d ", w[i]);
		exit (0); return;
	}
	for (int i = 0; i < n; i++)
	  if (!u[i])
	  {
    
    
	  	w[q[now]] = i; u[i] = 1;
	  	if (check ()) dfs (now + 1);
	  	w[q[now]] = -1; u[i] = 0;
	  }
}

int main()
{
    
    
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++) w[i] = -1;
	for (int i = 1; i <= 3; i++) cin >> s[i];
	for (int j = n; j >= 1; j--)
	  for (int i = 1; i <= 3; i++)
	    if (!mark[s[i][j - 1] - 'A' + 1])
	      mark[s[i][j - 1] - 'A' + 1] = 1, q[++q[0]] = s[i][j - 1] - 'A' + 1;
	dfs (1);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43010386/article/details/112966352