HDU ACM 2234 无题I->IDA*算法

分析:IDA*解决,借鉴大牛的启发式函数h(): 可以考虑把每一行上的数转化成相同的,或者把每一列上的数字转化成相同的,二者取最小值。

例如:
1 1 3 2
2 4 4 2       
3 3 1 4
1 2 3 4
把这个矩阵转化成行合法矩阵需要的操作:第一行至少要2次,第二行也是2次, 第三行是2次,第四行是3次, 所以把矩阵转化成行相同至少要3次。

#include<iostream>
using namespace std;

int map[5][5];
int deep;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))

bool check()         //检查是否是合法状态
{
	int i,j;

	if(map[1][1]!=map[1][2])
	{
		for(i=1;i<=4;i++)
			for(j=1;j<=4;j++)
				if(map[j][i]!=map[i][i])
					return false;
	}
	else
	{
		for(i=1;i<=4;i++)
			for(j=1;j<=4;j++)
				if(map[i][j]!=map[i][i])
					return false;
	}
	return true;
}

int get_h()         //IDA*的估价函数,获取每行或每列不在合法位置的数量
{
	int r=0,c=0,i,j;

	for(i=1;i<=4;i++)         //每行
	{
		int ans=0;
		int h[5]={0};
		for(j=1;j<=4;j++) h[map[i][j]]++;
		for(j=1;j<=4;j++)ans=max(ans,h[j]);
		r=max(4-ans,r);
	}
	for(j=1;j<=4;j++)         //每列
	{
		int ans=0;
		int h[5]={0};
		for(i=1;i<=4;i++) h[map[i][j]]++;
		for(i=1;i<=4;i++)ans=max(ans,h[i]);
		c=max(4-ans,c);
	}
	return min(r,c);
}

void mov_l(int i)
{
	int j,t;

	t=map[i][1];
	for(j=2;j<=4;j++)
		map[i][j-1]=map[i][j];
	map[i][4]=t;
}

void mov_r(int i)
{
	int j,t;

	t=map[i][4];
	for(j=4;j>=2;j--)
		map[i][j]=map[i][j-1];
	map[i][1]=t;
}

void mov_u(int j)
{
	int i,t;

	t=map[1][j];
	for(i=2;i<=4;i++)
		map[i-1][j]=map[i][j];
	map[4][j]=t;
}

void mov_d(int j)
{
	int i,t;

	t=map[4][j];
	for(i=4;i>=2;i--)
		map[i][j]=map[i-1][j];
	map[1][j]=t;
}

bool IDA_Star(int step)
{
	int i;

	if(step==deep)
		return check();
	if(step+get_h()>deep)   //估价函数剪枝
		return false;

	for(i=1;i<=4;i++)      //每行
	{
		mov_l(i);
		if(IDA_Star(step+1))
			return true;
		mov_r(i);           //恢复

		mov_r(i);
		if(IDA_Star(step+1))
			return true;
		mov_l(i);           //恢复
	}

	for(i=1;i<=4;i++)      //每列
	{
		mov_u(i);
		if(IDA_Star(step+1))
			return true;
		mov_d(i);           //恢复

		mov_d(i);
		if(IDA_Star(step+1))
			return true;
		mov_u(i);           //恢复
	}
	return false;
}

int main()      
{
	int t,i,j;
	
	cin>>t;
	while(t--)
	{
		for(i=1;i<=4;i++)
			for(j=1;j<=4;j++)
				cin>>map[i][j];
		if(check())              //判断开始是否合法
		{
			cout<<"0"<<endl;
			continue;
		}
		deep=1;
		while(deep<=5)
		{
			if(IDA_Star(0))
				break;
			deep++;
		}
		if(deep<=5)
			cout<<deep<<endl;
		else
			cout<<"-1"<<endl;
	}
    return 0;      
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。