虫食算(tyvj 1131)

9 篇文章 0 订阅

tyvj 1131:

搜索题,但是这题的重点在于减枝,下面是题解里写的:

对于一个测试数据
5
ABCED
BDACE
EBBAA
一:剪枝:
如最后一列的D,E,A
如果D,E,A的值都已经搜出来一种方案了,那么A =(D+E) mod n 即D+E除以n的余数是A,因为D+E有可能〉n并且进位,所以要mod n,详细一点即,对于搜索出来的D,E,A如果上一位进位则 A=(D+E+1)mod n,不进位则A=(D+E)mod n,不知道是否进位则(A=(D+E+1)mod n)or( A=(D+E)mod n),如果满足这些条件则继续,否则退出。
如果只知道D,E则(D+E)mod n(如进位则是(D+E+1)mod n)这个数没被赋值到其他的字母上去就可以继续搜,同样只知道E,A和D,A也可以这样剪枝。
E,A:[A-E mod n] (进位则是 (A-E-1) mod n)没被赋给除D外的其它字母
D,A:[A-D mod n] (进位则是 (A-D-1) mod n)没被赋给除E外的其它字母
二:优化:
还有一个优化就是从搜索顺序的优化:搜索顺序的改变也成为大大提高程序效率的关键:从右往左,按照字母出现顺序搜索,有很大程度上提高了先剪掉废枝的情况。
三:注意:
进位情况要特别注意:
(1)
如果D,E,A都知道,那么(D+E)DIV n<>0则进位否则不进(上一位进位则(D+E+1)DIV n<>0 )
(2)
如果知道D,E那么(D+E)DIV n<>0则进位否则不进(上一位进位则(D+E+1)DIV n<>0 ) 特殊情况:如果上一位不确定是否进位那么又要分情况讨论:○1如果进位,不进位两种情况中只有一种情况合法(即所确定的数符合剪枝条件),那么就按这种情况确定是不是进位。○2如果两种情况都合法则,如果两种情况的进位是否都相同,那么可以确定这一位是否进位,不同的话则进位状态赋值为待定。
(3)
知道A,E那么 A<E则进位否则不进(上一位进位则(A-1)<E ) 特殊情况:同(2)。
(4)
知道A,D那么 D<E则进位否则不进(上一位进位则(A-1)<D ) 特殊情况:同(2)。
(5)
只知道D,E,A中一个的值,则进位状态待定。


#include <stdio.h>
#include <string.h>

int n;
char s[3][30];
int let[27];//let[i]=a表示数字i代表的是a+'A'字母 
int b[27], bef[27], x, flag;
//b[i]=a表示i+'A'字母代表数字a,bef数组存放的是字母出现的先后顺序,这样搜索效率比较高 

int f()
{
	int temp = 0, l = 0, i;//l为进位 
	for(i = n - 1; i >= 0; i--)
	{
		temp = (b[s[0][i] - 'A'] + b[s[1][i] - 'A'] + l) % n;
		l = (b[s[0][i] - 'A'] + b[s[1][i] - 'A'] + l) / n;
		if(temp != b[s[2][i] - 'A'])
			return 0;
	}
	return 1;
}

int check()
{
	int temp, t1, t2, t3, i;
	for(i = n - 1; i >= 0; i--)
	{
		t1 = s[0][i] - 'A';
		t2 = s[1][i] - 'A';
		t3 = s[2][i] - 'A';
		if(b[t1] != -1 && b[t2] != -1 && b[t3] != -1)
			if((b[t1] + b[t2]) % n == b[t3] || (b[t1] + b[t2] + 1) % n == b[t3])//注意还要考虑有进位的情况 
				continue;
			else
				return 0;
		if(b[t1] != -1 && b[t2] != -1)
		{
			temp = (b[t1] + b[t2]) % n;
			//如果数字temp和temp+1(有进位)都已经被使用过就返回0
			//有其中一个或两个没有被使用过,就说明b[t1]+b[t2]=temp可能成立 
			if(let[temp] == -1 || let[(temp + 1) % n] == -1)
				continue;
			else
				return 0;
		}
		if(b[t1] != -1 && b[t3] != -1)
		{
			temp = b[t3] - b[t1];
			if(temp >= 0 && let[temp] == -1)
				continue;
			temp += n;//如果temp是负数,那么就加上n再进行判断 
			if(temp >= 0 && let[temp] == -1)
				continue;
			temp = b[t3] - b[t1] - 1;//考虑进位 
			if(temp >= 0 && let[temp] == -1)
				continue;
			temp += n;
			if(temp >= 0 && let[temp] == -1)
				continue;
			return 0;
		}
		if(b[t2] != -1 && b[t3] != -1)
		{
			temp = b[t3] - b[t2];
			if(temp >= 0 && let[temp] == -1)
				continue;
			temp += n;
			if(temp >= 0 && let[temp] == -1)
				continue;
			temp = b[t3] - b[t2] - 1;
			if(temp >= 0 && let[temp] == -1)
				continue;
			temp += n;
			if(temp >= 0 && let[temp] == -1)
				continue;
			return 0;
		}
	}
	return 1;
} 

void dfs(int k)
{
	int i;
	if(k == n)
	{
		if(f())
			flag = 1;
		return;
	}
	for(i = n - 1; i >= 0; i --)
	{
		if(let[i] == -1)
		{//数字i还没有被用过 
			let[i] = bef[k];
			b[bef[k]] = i;
			int ok;
			if(check())
				dfs(k + 1);
			if(flag)
				return ;
			let[i] = -1;
			b[bef[k]] = -1;
		}
	}
}

int main (void)
{
	while(scanf("%d", &n) != EOF)
	{
		scanf("%s%s%s", s[0], s[1], s[2]);
		int i, j;
		memset(b, 0, sizeof(b));
		memset(let, -1, sizeof(let));
		x = 0;
		flag = 0;
		for(i = n - 1; i >= 0; i--)
		{
			for(j = 0; j < 3; j++)
			{
				if(b[s[j][i] - 'A'] == 0)
				{
					b[s[j][i] - 'A'] = -1;
					bef[x ++] = s[j][i] - 'A';
				}
			}
		}
		dfs(0);
		for(i = 0; i < n; i++)
			printf("%d ", b[i]);
	}
	return 0;
}

刚开始就是全部搜索完再判断是否成立,个人觉得应该是超时,但是为什么是WA啊= =还特意看了两组数据,程序跑出来的明明也对……顺便贴几个测试数据把……

8
ABCDEFAG
DEABCGED
BEEHBDBC

5 7 4 1 2 6 3 0


5
ABCED
BDACE
EBBAA

1 0 3 4 2


8
ABDEBEHG
FGDBBAGB
EDEDCHGE

2 1 3 7 6 4 5 0


21
BADCEFGHIJKLMNOPQRSTU
BADCEFGHIJKLMNOPQRSTU
BDEGIKMOQTBDEGIKMOQST

1 0 3 2 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值