UVA - 321 The New Villa(bfs+hash)


 The New Villa 

Mr. Black recently bought a villa in the countryside. Only one thing bothers him: although there are light switches in most rooms, the lights they control are often in other rooms than the switches themselves. While his estate agent saw this as a feature, Mr. Black has come to believe that the electricians were a bit absent-minded (to put it mildly) when they connected the switches to the outlets.

One night, Mr. Black came home late. While standing in the hallway, he noted that the lights in all other rooms were switched off. Unfortunately, Mr. Black was afraid of the dark, so he never dared to enter a room that had its lights out and would never switch off the lights of the room he was in.

After some thought, Mr. Black was able to use the incorrectly wired light switches to his advantage. He managed to get to his bedroom and to switch off all lights except for the one in the bedroom.

You are to write a program that, given a description of a villa, determines how to get from the hallway to the bedroom if only the hallway light is initially switched on. You may never enter a dark room, and after the last move, all lights except for the one in the bedroom must be switched off. If there are several paths to the bedroom, you have to find the one which uses the smallest number of steps, where ``move from one room to another'', ``switch on a light'' and ``switch off a light'' each count as one step.

Input

The input file contains several villa descriptions. Each villa starts with a line containing three integers rd, and sr is the number of rooms in the villa, which will be at most 10. d is the number of doors/connections between the rooms and s is the number of light switches in the villa. The rooms are numbered from 1 to r; room number 1 is the hallway, room number r is the bedroom.

This line is followed by d lines containing two integers i and j each, specifying that room i is connected to room j by a door. Then follow slines containing two integers k and l each, indicating that there is a light switch in room k that controls the light in room l.

A blank line separates the villa description from the next one. The input file ends with a villa having r = d = s = 0, which should not be processed.

Output

For each villa, first output the number of the test case (`Villa #1'`Villa #2', etc.) in a line of its own.

If there is a solution to Mr. Black's problem, output the shortest possible sequence of steps that leads him to his bedroom and only leaves the bedroom light switched on. (Output only one shortest sequence if you find more than one.) Adhere to the output format shown in the sample below.

If there is no solution, output a line containing the statement `The problem cannot be solved.'

Output a blank line after each test case.

Sample Input

3 3 4
1 2
1 3
3 2
1 2
1 3
2 1
3 2

2 1 2
2 1
1 1
1 2

0 0 0

Sample Output

Villa #1
The problem can be solved in 6 steps:
- Switch on light in room 2.
- Switch on light in room 3.
- Move to room 2.
- Switch off light in room 1.
- Move to room 3.
- Switch off light in room 2.

Villa #2
The problem cannot be solved.


题目大意:
一个2B青年赚钱了于是乐呵呵地跑去买了一栋别墅,结果却发现这栋别墅的电灯电路都接错了,每个房间里的电灯开关控制的不是这个房间的电灯,而是另一个房间的电灯,2B青年很生气,后果很严重,于是严重谴责了装修工人。
一天晚上2B青年回到家里,站在大厅,发现除了大厅其它房间的电灯全部都是灭的。2B青年很怕黑,不敢走进没开灯的房间。所以问题来了,他该怎样从大厅走到自己的卧室?
2B青年还是很聪明的,他发现正好可以利用电灯开关接错而把另一个房间的电灯打开,然后就可以走进开了灯的那个房间(2B青年不会穿墙术 ,所以这两个房间当然必须是相邻的并且有门的)。
2B青年也是个很节约用电的好青年,所以当他走到卧室时,要求其它房间都必须把灭掉。
现在是你大显身手的时候,编写一个程序帮2B青年找出一个步骤最少的方案并且输出。 开灯,关灯,走进另一个房间都算是一个步骤。
如果找不出方案的话,2B青年今晚就得睡大厅沙发了……

这上面翻译的很好啊,感觉shuangde800大神写的题解都很详细啊,赞一个。


解析:这题参考了网络上的题解敲出来代码,学到了很多东西,主要是用到了bfs+hash


1. bfs时用0来表示灯亮,1灯亮,并把当前这个状态压入队列中,并用hash来进行判重。

2. 在搜索函数中,会进行这几个动作,从而产生新的状态, 然后把新状态压入队列(bfs),之后再对新状态又产生新的状态……一般都会有一个“目标状态”, 当从初始状态一直做动作直到状态转移成目标状态, 那么搜索就完成。

3. 开一个fa数组来记录上一级的状态,这样最后就能用递归求出过程了。

4. 判断重复的时候我主要是用到了set型的hash,因为这样比较简单。

#include <stdio.h>
#include <cstring>
#include <set>
using namespace std;

const int MAXSTATE = 1<<16;
const int N = 15;
typedef int State[N];
bool door[N][N];
bool edge[N][N];

struct Path{
	char action[50];
	int v;
};
const char action[3][100] = {
	"- Move to room",
	"- Switch on light in room",
	"- Switch off light in room"
};

State q[MAXSTATE];
int fa[MAXSTATE];
int dist[MAXSTATE];
Path path[MAXSTATE];
int r,d,s;

void print_path(int cur) {
	if(cur != 1) {
		print_path(fa[cur]);
		printf("%s %d.\n",path[cur].action,path[cur].v);
	}
}
bool isOk(State& s) {
	for(int i = 1; i < r; i++) {
		if(s[i]) {
			return false;
		}
	}
	if(s[r] == 2) {
		return true;
	}
	return false;
}
bool move(State& s,int u,int v,int i) {
	switch(i) {
		case 0: //从u移动到v
			if(door[u][v] && s[v]) {
				s[u] = 1;
				s[v] = 2;
				return true;
			}
			return false;
		case 1://从u打开v的电灯
			if(edge[u][v] && !s[v]) {
				s[v] = 1;
				return true;
			}
			return false;
		case 2://从u关闭v的电灯
			if(edge[u][v] && s[v]) {
				s[v] = 0;
				return true;
			}
			return false;
	}
}
set<int> vis;
void init_lookup_table() {
	vis.clear();
}
int hash(int s) {
	int sum = 0;
	for(int i = 1; i <= r; i++) {
		sum = sum * 3 + q[s][i] + 1;
	}
	return sum;
}
bool try_to_insert(int s) {
	int v = hash(s);
	if(vis.count(v)) {
		return false;
	}
	vis.insert(v);
	return true;
}
int bfs() {
	init_lookup_table();
	int rear,front;
	rear = front = 1;
	q[rear++][1] = 2;
	while(front < rear) {
		State& s = q[front];
		if(isOk(s)) {
			return front;
		}
		int u;
		for(u = 1; u <= r; u++) {
			if(s[u] == 2) {
				break;
			}
		}
		for(int v = 1; v <= r; v++) {
			if(u == v) {
				continue;
			}
			for(int i = 0; i < 3; i++) {
				State& t = q[rear];
				memcpy(t,s,sizeof(s));
				if(move(t,u,v,i)) {
					if(try_to_insert(rear)) {
						fa[rear] = front;
						dist[rear] = dist[front] + 1;
						strcpy(path[rear].action,action[i]);
						path[rear].v = v;
						rear++;
					}

				}
			}
		}
		front++;
	}
	return 0;
}
int main() {
	int u,v;
	int cas = 1;
	while(scanf("%d%d%d",&r,&d,&s) != EOF && (r || d || s)) {
		memset(door,0,sizeof(door));
		memset(edge,0,sizeof(edge));
		for(int i = 1; i <= d; i++) {
			scanf("%d%d",&u,&v);
			door[u][v] = door[v][u] = true;
		}
		for(int i = 1; i <= s; i++) {
			scanf("%d%d",&u,&v);	
			edge[u][v] = true;
		}
		int ans = bfs();
		printf("Villa #%d\n",cas++);
		if(ans) {
			printf("The problem can be solved in %d steps:\n",dist[ans]);
			print_path(ans);
		}else {
			printf("The problem cannot be solved.\n");
		}
		printf("\n");
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值