luogu1092:虫吃算:深搜+剪枝

题目连接:该题是luogu试炼场的2-7:T6


题目大意:
1 给出一个3*n的字母棋盘,要求用[0,n)这n个数字替换棋盘里的字母,使得棋盘形成一个n进制的合法的竖式。


解题思路:经典的深搜复杂题,NOIP2004的 T4
1 按照位置搜索,N的最大之是26,所以会超时;
2 想剪枝:进位的处理,数字的差重。
3 玄学:枚举的时候从大到小会优化很多时间。


上代码:
 

//luogu1092: 虫吃算
//棋盘深搜+剪枝


#include<bits/stdc++.h>
using namespace std;

int n;
int a[5][110],b[110],f[110];
char st[110];

void inp()//1:输入与转换 :a1+a2=a3
{
	scanf("%d",&n);
	for(int i=1;i<=3;i++)
	{
		scanf("%s",st+1);
		for(int j=1;j<=n;j++) a[i][j]=st[j]-'A'+1;
	}
}
bool pd2()//过程判断:1:最高位;2:各数位进位情况 
{
	if(f[a[1][1]]+f[a[2][1]]>=n) return 0;//最高位不可进位
	
	for(int i=n;i>=1;i--)
	{
		int x=f[a[1][i]],y=f[a[2][i]],z=f[a[3][i]];
		
		if(x==-1||y==-1||z==-1) continue;//未处理到
		
		if((x+y)%n!=z&&(x+y+1)%n!=z) return 0;//无法匹配 
	} 
	return 1;	
}

bool ch()//是否有数字没用完 
{
	for(int i=1;i<=n;i++) if(f[i]==-1) return 0;
	return 1;
}

bool pd()//最终判断:式子是否合法 
{
	int k=0;//进位的值 
	for(int i=n;i>=1;i--)
	{
		int x=f[a[1][i]],y=f[a[2][i]],z=f[a[3][i]];
		
		if((x+y+k)%n!=z) return 0;//不合法 
		
		k=(x+y+k)/n;//下次的进位 
	}
	return 1; 
}

void dfs(int x,int y,int t)//x行y列,进位是t 
{
	if(ch()||y==0)//判断是否全部数字都用完了或者全盘扫描了: 
	{
		if(pd()) //式子完全合法 
		{
			for(int i=1;i<=n;i++) printf("%d ",f[i]);
			exit(0);//终结 
		} 
		return ;
	}

	if(pd2()==0) return ;//剪枝:过程进位判断
	
	//以上是判断与剪枝 
	//===============================================
	
	//以下是每一次的执行 
	if(f[a[x][y]]==-1)//当前位,没被赋值
	{
		for(int i=n-1;i>=0;i--)
		{
			
			if(b[i]==0)//i没被用过,可用: 
			{
				
				if(x<3)//一二行 
				{
					f[a[x][y]]=i;
					b[i]=1;
					dfs(x+1,y,t);//同列,下一行
					b[i]=0;
					f[a[x][y]]=-1; 
				}
				else if(x==3)//第三行 
				{
					int z=f[a[1][y]]+f[a[2][y]]+t;
					if(z%n!=i) continue;
					
					f[a[x][y]]=i;
					b[i]=1;
					dfs(1,y-1,z/n);//向左一位
					b[i]=0; 
					f[a[x][y]]=-1;
				}
			}
		} 
	}
	else//当前位已取值 
	{
		if(x<3) dfs(x+1,y,t);
		
		else//第三行
		{
			int z=f[a[1][y]]+f[a[2][y]]+t;
			dfs(1,y-1,z/n); //左移一位 
		}
	}
}

int main()
{
	freopen("testdata.in","r",stdin);
	inp();//输入与整理
	 
	memset(f,-1,sizeof(f));//i字符表示的f[i]的值 
	memset(b,0,sizeof(b));//i数字是否用过 
	
	dfs(1,n,0);//从第1行第n列开始,进位是 0
	
	return 0;
}
 

猜你喜欢

转载自blog.csdn.net/liusu201601/article/details/89085183