2016-CCOQR-Q2 Through A Maze Darkly - Solution
IO
int get_next_int()
{
int n;
scanf("%d", &n);
return n;
}
Data Storage
Note the use of a structure to keep the data together. Since this problem is very dependent of accessing memory quickly keeping the required data together is critical. Also note that we are using an unordered_map container. This is one of the keys to making this code execute quickly.
typedef struct
{
int nextRoom;
int nextDoor;
bool valid;
} RoomDoor;
typedef struct
{
int doorCount;
RoomDoor* doors;
std::unordered_map<int, int> doorMap;
} Room;
Read Input
int totalRooms;
Room* rooms;
void read_input()
{
totalRooms = get_next_int();
rooms = new Room[totalRooms];
for (int room = 0; room < totalRooms; room++)
{
int doorCount = get_next_int();
rooms[room].doorCount = doorCount;
rooms[room].doors = new RoomDoor[doorCount];
for (int door = 0; door < doorCount; door++)
{
int nextRoom = get_next_int() - 1; // 0-Based Index
rooms[room].doors[door].nextRoom = nextRoom;
rooms[room].doors[door].valid = true;
rooms[nextRoom].doorMap[room] = door; // Store the reverse Lookup to the door
}
}
}
Next Door Pre-computation
void precompute_next_door()
{
for (int room = 0; room < totalRooms; room++)
{
int roomDoorCount = rooms[room].doorCount;
for (int door = 0; door < roomDoorCount; door++)
{
int nextRoom = rooms[room].doors[door].nextRoom;
int nextDoor = rooms[room].doorMap[nextRoom] - 1;
if (nextDoor == -1)
nextDoor = rooms[nextRoom].doorCount - 1;
rooms[room].doors[door].nextDoor = nextDoor;
}
}
}
Solver
int* roomMaxPathDistance;
int* roomStartDistance;
void init_solver()
{
roomMaxPathDistance = new int[totalRooms];
roomStartDistance = new int[totalRooms];
for (int i = 0; i < totalRooms; i++)
roomMaxPathDistance[i] = 0;
}
void init_distances()
{
for (int room = 0; room < totalRooms; room++)
roomStartDistance[room] = -1;
}
void process_door(int room, int distance)
{
if (roomStartDistance[room] == -1)
{
// Start Measuring
roomStartDistance[room] = distance;
}
else
{
// Compute Distance from starting point
int path_distance = distance - roomStartDistance[room];
// Only keep the maximum
if (path_distance > roomMaxPathDistance[room])
roomMaxPathDistance[room] = path_distance;
// Start measuring again from here
roomStartDistance[room] = distance;
}
}
void solve_path(int startRoom, int startDoor)
{
int currentRoom = startRoom;
int currentDoor = startDoor;
int distance = 0;
int pass = 0;
void init_distances();
do
{
// Process this room
process_door(currentRoom, distance);
// Remove this door from the system
rooms[currentRoom].doors[currentDoor].valid = false;
// What room is next?
int nextRoom = rooms[currentRoom].doors[currentDoor].nextRoom;
int nextRoomDoor = rooms[currentRoom].doors[currentDoor].nextDoor;
// Increase distance
distance++;
// Switch rooms
currentRoom = nextRoom;
currentDoor = nextRoomDoor;
// Did we hit the starting room/door?
if (currentRoom == startRoom && currentDoor == startDoor)
pass++;
} while (pass < 2);
}
void solve_rooms()
{
init_distances();
for (int room = 0; room < totalRooms; room++)
{
int roomDoorCount = rooms[room].doorCount;
for (int door = 0; door < roomDoorCount; door++)
{
// Only solve room/doors that have not been explored
if (rooms[room].doors[door].valid)
solve_path(room, door);
}
}
}
Data Output
void answer_questions()
{
int totalQuestions = get_next_int();
for (int q = 0; q < totalQuestions; q++)
{
int question = get_next_int() - 1; // 0 Based Index
printf("%d\n", roomMaxPathDistance[question]);
}
}
Main
int main()
{
read_input();
precompute_next_door();
init_solver();
solve_rooms();
answer_questions();
return 0;
}