1 条题解
-
0
题意分析
本题描述了一个别墅的场景,别墅中有多个房间,房间之间有门相连,每个房间可能有控制其他房间灯的开关。布莱克先生从走廊(1号房间)出发,要在不进入黑暗房间且最后只有卧室(r号房间)灯亮的情况下到达卧室。要求编写程序找到从走廊到卧室的最短路径,其中“从一个房间移动到另一个房间”、“打开一盏灯”和“关掉一盏灯”都算作一步。
解题思路
- 数据结构定义:
statusN
结构体用于表示状态,包括房间号rNum
、灯光状态bit
、步数step
和指向下一个状态的指针next
。doorN
结构体用于表示门,包括两个房间号f
和t
,以及一个方法getOpp
用于获取门的另一端房间号。controlN
结构体用于表示开关,包括控制的房间号hNum
和被控制的房间号lNum
。
- 初始化:
- 初始化
exp
数组,用于表示每个房间灯的状态值(2的幂次方)。 - 初始化
status
数组,包含所有可能的状态(房间号和灯光状态组合)。 - 初始化
v
数组,用于记录每个状态是否已访问。
- 初始化
- BFS 搜索:
- 从初始状态(走廊灯亮,其他灯灭)开始,使用队列进行广度优先搜索。
- 对于当前状态,检查是否到达目标状态(卧室灯亮,其他灯灭),如果是则结束搜索。
- 否则,尝试通过门移动到相邻房间(如果相邻房间灯亮且未访问过),或者通过开关改变当前房间灯的状态(如果有对应的开关且新状态未访问过),并将新状态加入队列。
- 输出结果:
- 如果找到解决方案,输出测试用例编号和最短步骤序列。
- 如果没有找到解决方案,输出“The problem cannot be solved.”。
复杂度分析
- 时间复杂度:
- 初始化部分的时间复杂度主要取决于循环的次数,对于
exp
数组的初始化,循环次数为MAX_H
,时间复杂度为 ;对于status
数组的初始化,循环次数为MAX_H * MAX_S
,时间复杂度为 。 - 在 BFS 搜索过程中,每个状态最多被访问一次,对于每个状态,最多需要检查
doorNum
个门和switNum
个开关,因此时间复杂度为 。 - 总体时间复杂度为 $O(MAX_H * MAX_S + (doorNum + switNum) * MAX_H * MAX_S) = O((doorNum + switNum + 1) * MAX_H * MAX_S)$。
- 初始化部分的时间复杂度主要取决于循环的次数,对于
- 空间复杂度:
- 主要的空间占用是
status
数组和v
数组,它们的大小均为(MAX_H + 2) * (MAX_S + 2)
,因此空间复杂度为 。
- 主要的空间占用是
代码实现
#include <iostream> #include <queue> #include <algorithm> #define MAX_S 1024 #define MAX_H 10 using namespace std; struct statusN { int rNum, bit, step; statusN *next; }status[MAX_H + 2][MAX_S + 2]; struct doorN { int f, t; int getOpp(int curS) //-1 not exist { if(curS == f) return t; else if(curS == t) return f; else return -1; } }door[MAX_H * MAX_H + 2]; struct controlN { int hNum, lNum; }control[MAX_H * MAX_H + 2]; int v[MAX_H + 2][MAX_S + 2]; int exp[MAX_H + 2]; int roomNum, doorNum, switNum; int getLight(int ex) { for(int i = 0; i < roomNum; i++) if(exp[i] == ex) return i; return -1; } void print(statusN *cur) { if(!cur->next) return; print(cur->next); int bitT = cur->bit, bitF = cur->next->bit, room2 = cur->rNum, room1 = cur->next->rNum; if(bitT == bitF) cout<<"- Move to room "<<room2+1<<"."<<endl; else { int ex = bitF ^ bitT; int which = getLight(ex); if(ex & bitT) cout<<"- Switch on light in room "<<getLight(ex) + 1<<"."<<endl; else cout<<"- Switch off light in room "<<getLight(ex) + 1<<"."<<endl; } } bool solve() { // 将 memset 替换为循环初始化 for (int i = 0; i < MAX_H + 2; ++i) { for (int j = 0; j < MAX_S + 2; ++j) { v[i][j] = 0; } } statusN *final = &status[0][exp[0]]; final->next = NULL; final->step = 0; queue<statusN *> Q; v[0][exp[0]] = true; Q.push(final); bool finish = false; statusN *cur; int i; while(!Q.empty()) { cur = Q.front(); Q.pop(); int bit = cur->bit, room = cur->rNum, step = cur->step; if(bit == exp[roomNum - 1] && room == roomNum - 1) { finish = true; break; } for(i = 0; i < doorNum; i++) { int opp; if((opp = door[i].getOpp(room))!= -1 && (bit & exp[opp]) > 0 && (!v[opp][bit])) { v[opp][bit] = 1; statusN *ns = &status[opp][bit]; ns->next = cur; ns->step = step + 1; Q.push(ns); } } for(i = 0; i < switNum; i++) { int ctrlNum = control[i].lNum; if(control[i].hNum == room) { int newBit = bit ^ exp[ctrlNum]; if(v[room][newBit]) continue; v[room][newBit] = 1; statusN *ns = &status[room][newBit]; ns->next = cur; ns->step = step + 1; Q.push(ns); } } } if(!finish) return false; cout<<"The problem can be solved in "<<cur->step<<" steps:"<<endl; cur = &status[roomNum - 1][exp[roomNum - 1]]; print(cur); return true; } bool compare(controlN c1, controlN c2) { if(c1.hNum < c2.hNum) return true; else if(c1.hNum == c2.hNum) { if(c1.lNum <= c2.lNum) return true; return false; } return false; } int main() { int i, j, f, t; exp[0] = 1; for(i = 1; i <= MAX_H; i++) exp[i] = exp[i - 1]<<1; for(i = 0; i < MAX_H; i++) { for(j = 0; j < MAX_S; j++) { statusN cur = {i, j, 0, NULL}; status[i][j] = cur; } } int caseN = 0; while(cin>>roomNum>>doorNum>>switNum && (roomNum + doorNum + switNum)!= 0) { caseN++; for(i = 0; i < doorNum; i++) { cin>>f>>t; doorN cur = {f - 1, t - 1}; door[i] = cur; } for(i = 0; i < switNum; i++) { cin>>f>>t; if(f == t) { switNum--; i--; continue; } controlN cur = {f - 1, t - 1}; control[i] = cur; } cout<<"Villa #"<<caseN<<endl; sort(control, control + switNum, compare); if (!solve()) cout<<"The problem cannot be solved."<<endl; cout<<endl; } return 0; }
- 数据结构定义:
- 1
信息
- ID
- 138
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者