uva 10274 Fans and Gems

搞了一整个晚上,终于把这道神题调通了,真心有点复杂,涉及到哈希查重,广搜,深搜,虽然调通了但是思路还是有些冗杂,代码页不够简洁,敲键盘敲得手都麻了,先把代码粘上来吧。做的时候要进行适当剪枝,对于那种有单个彩色方块的状态,已经不可能再产生解决方案了,直接剪掉,可以提高效率,一开始一直run time error,后来发现是读数据的格式有问题,这种每一组数据中间有空行的数据格式还是用gets配合sscanf的形式读取数据最保险,以后要注意了。

#include <stdio.h>
#include <set>
#include <queue>
#include <list>
#include <map>
#include <string.h>
using namespace std;

typedef unsigned char node_type;
typedef unsigned char DIRECTION;
#define		RED			1
#define		GREEN		2
#define		BLUE		3
#define		FLYER		4
#define		MAX_ROW		13
#define		MAX_COL		21
#define		MAX_HASH_SIZE	2000003
#define		UP			1
#define		DOWN		2
#define		LEFT		3
#define		RIGHT		4

int max_row_g;
int max_col_g;


struct state
{
	char m[MAX_ROW][MAX_COL]; //当前的状态
	int step; //达到状态的步数
	char solution[30]; //记录走过的路径
};


typedef int HASH_VALUE;
typedef struct state STATE;

map< HASH_VALUE, list<STATE> > hash_map;

bool operator < (const struct state &a, const struct state &b)
{
	if(a.step > b.step)
		return true;
	if(a.step < b.step)
		return false;
	else
	{
		char buf_a[20];
		char buf_b[20];

		memcpy(buf_a, a.solution+1, a.step);
		memcpy(buf_b, b.solution+1, a.step);
		buf_a[a.step] = '\0';
		buf_b[b.step] = '\0';

		if(strcmp(buf_a, buf_b) > 0)
			return true;
		else
			return false;
	}
}

priority_queue< struct state > pq; //优先队列

int _hash(const struct state &sta)
{
	int i, j;
	unsigned int v;

	v = 1;
	for(i=1; i<=max_row_g; i++)
		for(j=1; j<=max_col_g; j++)
			v = v*39+sta.m[i][j];

	return v%MAX_HASH_SIZE;
}

void print_arr(struct state &sta)
{
	for(int i=1; i<=max_row_g; i++)
	{
		for(int j=1; j<=max_col_g; j++)
			printf("%c", sta.m[i][j]);
		printf("\n");
	}
}

//把一种状态插入到哈希表里面
void insert_state2hash_table(struct state &sta)
{
	int hv;

	hv = _hash(sta);
	hash_map[hv].push_back(sta);
}

bool is_visited(struct state &sta)
{
	int hv;

	hv = _hash(sta);
	if(hash_map.find(hv) == hash_map.end())
		return false;

	list< STATE >::iterator it;
	bool res = false;
	int i, j;
	for(it=hash_map[hv].begin(); it!=hash_map[hv].end(); it++)
	{
		bool f;
		f = true; //是否完全一样
		for(i=1; i<=max_row_g; i++)
			for(j=1; j<=max_col_g; j++)
			{
				if(it->m[i][j] != sta.m[i][j])
				{
					f = false;
					break;
				}
			}

		if(f == true)
		{
			res = true; //在哈希表里面已经找到这种状态了
			break;
		}
	}

	return res;
}

//返回是否有方块移动过
bool blow(struct state &sta, DIRECTION direction)
{
	int i, j, end;
	bool moved = false;

	switch(direction)
	{
		case UP:
		{
			for(i=1; i<=max_row_g; i++) //应该从最上面一行开始
				for(j=1; j<=max_col_g; j++)
				{
					if(sta.m[i][j]!='#' && sta.m[i][j]!=' ') //可移动节点
					{
						for(end=i-1; end>=1; end--)
							if(sta.m[end][j] != ' ')
								break;
						end++;
						if(end != i)
						{
							sta.m[end][j] = sta.m[i][j];
							sta.m[i][j] = ' ';
							moved = true;
						}
					}
				}
			break;
		}

		case DOWN:
		{
			for(i=max_row_g; i>=1; i--) //应该从最下面一行开始
				for(j=1; j<=max_col_g; j++)
				{
					if(sta.m[i][j]!='#' && sta.m[i][j]!=' ') //可移动节点
					{
						for(end=i+1; end<=max_row_g; end++)
						if(sta.m[end][j] != ' ')
							break;

						end--;
						if(end != i)
						{
							sta.m[end][j] = sta.m[i][j];
							sta.m[i][j] = ' ';
							moved = true;
						}
					}
				}
			break;
		}

		case LEFT:
		{
			for(j=1; j<=max_col_g; j++) //从最左边一列开始
				for(i=1; i<=max_row_g; i++)
				{
					if(sta.m[i][j]!='#' && sta.m[i][j]!=' ') //可移动节点
					{
						for(end=j-1; end>=1; end--)
							if(sta.m[i][end] != ' ')
								break;

						end++;

						if(end != j)
						{
							sta.m[i][end] = sta.m[i][j];
							sta.m[i][j] = ' ';
							moved = true;
						}
					}
				}
			break;
		}

		case RIGHT:
		{
			for(j=max_col_g; j>=1; j--) //从最右边一列开始
				for(i=1; i<=max_row_g; i++)
				{
					if(sta.m[i][j]!='#' && sta.m[i][j]!=' ') //可移动节点
					{
						for(end=j+1; end<=max_col_g; end++)
							if(sta.m[i][end] != ' ')
								break;

						end--;
						if(end != j)
						{
							sta.m[i][end] = sta.m[i][j];
							sta.m[i][j] = ' ';
							moved = true;
						}
					}
				}

			break;
		}

	}

	return moved;
}

void dfs(struct state &sta, int i, int j, bool &has_delete, char delete_char, int last_count)
{
	if(!(i>=1 && i<=max_row_g))
		return;

	if(!(j>=1 && j<=max_col_g))
		return;

	if(sta.m[i][j]==' ' || sta.m[i][j]=='@' || sta.m[i][j]=='#')
		return;

	if(sta.m[i][j] == delete_char)
	{
		if(last_count >= 1)
		{
			sta.m[i][j] = ' ';
			has_delete = true;
		}

		dfs(sta, i-1, j, has_delete, delete_char, last_count+1);
		dfs(sta, i+1, j, has_delete, delete_char, last_count+1);
		dfs(sta, i, j-1, has_delete, delete_char, last_count+1);
		dfs(sta, i, j+1, has_delete, delete_char, last_count+1);
	}
	else
	{
		return;
	}
		
} 

//消除掉相同颜色的方块, 返回有没有消除过相同颜色的方块
bool clear_gem(struct state &sta)
{
	int i, j;
	bool has_delete; //有没有消除过方块
	bool res;

	res = false;
	for(i=1; i<=max_row_g; i++)
		for(j=1; j<=max_col_g; j++)
		{
			has_delete = false;
			dfs(sta, i, j, has_delete, sta.m[i][j], 0);
			if(has_delete)
			{
				res = true;
				sta.m[i][j] = ' ';
			}
		}

	return res;
}

//判断是不是所有彩色方块消除完毕的状态
bool is_last_state(const struct state &sta)
{
	int i, j;
	int res;

	res = true;
	for(i=1; i<=max_row_g; i++)
		for(j=1; j<=max_col_g; j++)
		{
			if(sta.m[i][j]=='1' || sta.m[i][j]=='2' || sta.m[i][j]=='3')
			{
				res = false;
				break;
			}
		}

	return res;
}

//查看有没有单个的彩色方块,有的话这种状态无解
bool can_solve(const struct state &sta)
{
	int count1, count2, count3;
	int i, j;

	count1 = count2 = count3 = 0;
	for(i=1; i<=max_row_g; i++)
		for(j=1; j<=max_col_g; j++)
		{
			if(sta.m[i][j] == '1')
				count1 ++;
			else if(sta.m[i][j] == '2')
				count2 ++;
			else if(sta.m[i][j] == '3')
				count3 ++;

		}

	if(count1==1 || count2==1 || count3==1)
		return false;

	return true;
}

void bfs()
{
	struct state sta, sta_top;
	int i, j, end;

	while(!pq.empty())
	{
		memcpy(&sta_top, &(pq.top()), sizeof(struct state));
		pq.pop();
		
		if(is_last_state(sta_top))
		{
			for(i=1; i<=sta_top.step; i++)
				printf("%c", sta_top.solution[i]);
			printf("\n");
			return;
		}

		//printf("pop: step=%d\n", sta_top.step);
		//print_arr(sta_top);
		//printf("\n");

		//节点向下运动
		memcpy(&sta, &sta_top, sizeof(struct state));
		while(1)
		{
			if(!blow(sta, DOWN))
				break;
			if(!clear_gem(sta))
				break;
		}
		if(!is_visited(sta))
		{
			sta.step = sta_top.step+1;
			if(sta.step <=18 && can_solve(sta))
			{
				sta.solution[sta.step] = 'D';
				pq.push(sta);
				insert_state2hash_table(sta);

				//printf("push DOWN:\n");
				//print_arr(sta);
				//printf("\n");
			}
		}
		
		//节点向左运动
		memcpy(&sta, &sta_top, sizeof(struct state));
		while(1)
		{
			if(!blow(sta, LEFT))
				break;
			if(!clear_gem(sta))
				break;
		}
		if(!is_visited(sta))
		{
			sta.step = sta_top.step+1;
			if(sta.step <=18 && can_solve(sta))
			{
				sta.solution[sta.step] = 'L';
				pq.push(sta);
				insert_state2hash_table(sta);

				//printf("push LEFT:\n");
				//print_arr(sta);
				//printf("\n");
			}
		}

		//节点向右运动
		memcpy(&sta, &sta_top, sizeof(struct state));
		while(1)
		{
			if(!blow(sta, RIGHT))
				break;
			if(!clear_gem(sta))
				break;
		}
		if(!is_visited(sta))
		{
			sta.step = sta_top.step+1;
			if(sta.step <=18 && can_solve(sta))
			{
				sta.solution[sta.step] = 'R';
				pq.push(sta);
				insert_state2hash_table(sta);

				//printf("push RIGHT:\n");
				//print_arr(sta);
				//printf("\n");
			}
		}

		//节点向上运动
		memcpy(&sta, &sta_top, sizeof(struct state));
		while(1)
		{
			if(!blow(sta, UP))
				break;
			if(!clear_gem(sta))
				break;
		}
		if(!is_visited(sta))
		{
			sta.step = sta_top.step+1;
			if(sta.step <=18 && can_solve(sta))
			{
				sta.solution[sta.step] = 'U';
				pq.push(sta);
				insert_state2hash_table(sta);

				//printf("push UP:\n");
				//print_arr(sta);
				//printf("\n");
			}
		}
	}

	printf("-1\n");
}

void func(int m, int n, const struct state &sta)
{
	max_row_g = m;
	max_col_g = n;
	hash_map.clear();

	while(!pq.empty())
		pq.pop();

	pq.push(sta);
	hash_map[_hash(sta)].push_back(sta);

	bfs();

}

char buffer[100];
int main(void)
{
	int N, m, n;
	int i, j;
	struct state sta;

	//freopen("input.dat", "r", stdin);

	gets(buffer);
	sscanf(buffer, "%d", &N);
	sta.step = 0;
	while(N--)
	{
		gets(buffer);
		sscanf(buffer, "%d %d", &m, &n);
		for(i=1; i<=m; i++)
		{
			gets(sta.m[i]+1);
		}
		gets(buffer);
		func(m, n, sta);
	}

	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值