UVa 321 & ZOJ 1301 - The New Villa

26 篇文章 0 订阅
6 篇文章 0 订阅

传送门UVa 321 & ZOJ 1301 - The New Villa


第一次写这么长的代码。。各种艰难。

参考了shuangde800的解题报告。

从他的文章标题可以看出他对这题的深深怨念。。。。


题意是一个青年要从房子的走廊到他自己的房间里去,他不敢去黑暗的房间,幸好每个房间的开关在别的房间里。

给出数据,求他能不能到达卧室并关掉除了卧室之外的灯。


这题的“状态”是每个房间的灯的情况,和人所在的位置,所以只需要记录这个状态。

其他的和八数码差不多。。虽然如此,但是我还是在哈希函数上遇到了困难。。原来依然可以用BKDRHash来解决。。


还有扩展结点的时候的问题。。一开始我只想到循环三次,分别对应出门,关灯,开灯。。可是一个房间可以有很多开关的。。

最后在输出路径那里,只是把昨天那题变一下,加了一个房间编号,我就不会了。。(捂脸


具体的分析shuangde800已经讲很好了,大家参考他的吧。

终于可以安心写高数作业了╮(╯▽╰)╭


#include <cstdio>
#include <cstring>
using namespace std;
const int HashSize = 2000000;
const int MAXN = 300000;
const char action[][50] = {"- Move to room ", "- Switch off light in room ", "- Switch on light in room "}; 

typedef int State[11];

State qu[MAXN];
int head[HashSize], next[HashSize];
int room[11][11], swit[11][11], roomNum;
int father[MAXN], ans, step[MAXN];
char path[MAXN][35];

inline void BFS();
inline bool TryToInsert(int s);
inline bool IsOk(State &cur);
inline void Init();
inline bool Go(State &curState, int curLoca, int tarGet, int way);
inline int BKDHash(State &s);
inline void PrintPath(int cur);

int main()
{
	//freopen("input.txt", "r", stdin);
	int d, s, i, j, a, b, cases = 1;
	while (scanf("%d%d%d", &roomNum, &d, &s), roomNum + d + s)
	{
		memset(room, 0, sizeof(room));
		memset(swit, 0, sizeof(swit));
		for (i = 0; i < d; i++)
		{
			scanf("%d%d", &a, &b);
			room[a][b] = room[b][a] = 1;
		}
		for (i = 0; i < s; i++)
		{
			scanf("%d%d", &a, &b);
			swit[a][b] = 1;
		}
		BFS();
		printf("Villa #%d\n", cases++);
		if (ans != -1)
		{
			printf("The problem can be solved in %d steps:\n", step[ans]);
			PrintPath(ans);
		}
		else
			printf("The problem cannot be solved.\n");
		printf("\n");
	}
	return 0;
}

inline void BFS()
{
	int i, j;
	Init();
	int front = 0, rear = 1;
	while (front < rear)
	{
		State &curState = qu[front];	
		if (IsOk(curState))
		{
			ans = front;
			return;
		}
		int curLoca;
		for (i = 1; i <= roomNum; i++)
			if (curState[i] == 2)
			{
				curLoca = i;
				break;
			}
		for (i = 1; i <= roomNum; i++)
		{
			if (i != curLoca)
			{
				for (int j = 0; j < 3; j++)
				{
					State &t = qu[rear];
					memcpy(t, curState, sizeof(curState));
					if (Go(t, curLoca, i, j))
						if (TryToInsert(rear))
						{
							father[rear] = front;
							step[rear] = step[front] + 1;
							char str[4];  
							if (i < 10)
								str[0] = i + '0', str[1] = '.', str[2] = 0;
							if (i == 10)
								str[0] = '1', str[1] = '0', str[2] = '.', str[3] = 0;
							strcpy(path[rear], action[j]);
							strcat(path[rear], str);
							rear++;
						}
				}
			}
		}
		front++;
	}
	ans = -1;
}

inline bool TryToInsert(int s)
{
	int h = BKDHash(qu[s]);
	int u = head[h];
	while (u)
	{
		if (memcmp(qu[u], qu[s], sizeof(qu[h])) == 0)
			return 0;
		u = next[u];
	}
	next[s] = head[h];
	head[h] = s;
	return 1;
}

inline int BKDHash(State &s)
{
	int seed = 131;
	int Hash = 0;
	for (int i = 1; i <= roomNum; i++)
		Hash = Hash * seed + s[i];
	return (Hash & 0x7FFFFFFF) % HashSize;
}

inline bool IsOk(State &cur)
{
	int i;
	for (i = 1; i < roomNum; i++)
		if (cur[i])
			return false;
	if (cur[i] == 2)
		return true;
	return false;
}

inline bool Go(State &curState, int curLoca, int tarGet, int way)
{
	if (way == 0)
	{
		if (room[curLoca][tarGet] && curState[tarGet])
		{
			curState[tarGet] = 2; curState[curLoca] = 1;
			return true;
		}
	}
	else if (way == 1)
	{
		if (swit[curLoca][tarGet] && curState[tarGet])
		{
			curState[tarGet] = 0;
			return true;
		}
	}
	else if (way = 2)
	{
		if (swit[curLoca][tarGet] && !curState[tarGet])
		{
			curState[tarGet] = 1;
			return true;
		}	 
	}
	return false;
}

inline void Init()
{
	memset(head, 0, sizeof(head));
	memset(qu, 0, sizeof(qu));
	qu[0][1] = 2;
	father[0] = -1, step[0] = 0;
}

inline void PrintPath(int cur)
{
	if (father[cur] != -1)
	{
		PrintPath(father[cur]);
		printf("%s\n", path[cur]);
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值