/*
Problem: Walking through a grid following the pattern R -> B -> I -> K -> R -> ...
You start at any 'R' cell and can move up/down/left/right, but only to cells
that have the next letter in the sequence (R needs B, B needs I, I needs K, K needs R).
Scoring: Each time you complete a full RBIK cycle (stepping from K to R), you earn 1 point.
Output:
- "infinity" if you can loop forever
- Otherwise, the maximum points you can possibly earn
==================================================================================
HOW WE SOLVE THIS:
==================================================================================
Think of this grid as a maze where you can only move to specific neighbors.
STEP 1: Build a map of legal moves
- Look at each cell and figure out where you can go from there
- From an 'R' cell, you can only move to neighboring 'B' cells
- From a 'B' cell, you can only move to neighboring 'I' cells
- From an 'I' cell, you can only move to neighboring 'K' cells
- From a 'K' cell, you can only move to neighboring 'R' cells (and score a point!)
STEP 2: Can we walk in circles forever?
- Imagine you're walking through the grid following the rules
- If you ever come back to a cell you've already visited, you found a loop!
- If there's a loop, you can walk around it forever, scoring points each time
- So we check: is there any loop we can reach from a starting 'R'?
- If yes → answer is "infinity"
STEP 3: Find the best path (if there's no loop)
- Since there's no loop, every path must eventually end
- We want to find the path that scores the most points
- We use a smart technique: process cells in an order where we always know
the best way to reach each cell before we try to move past it
- This is called "topological sort" - it's like processing tasks where some
tasks must be done before others
Example walkthrough:
Grid: R B
K I
From R(0,0): can go to B(0,1) → score so far: 0
From B(0,1): can go to I(1,1) → score so far: 0
From I(1,1): can go to K(1,0) → score so far: 0
From K(1,0): can go back to R(0,0) → score +1 point! Total: 1
But wait! We're back at R(0,0) which we visited before → that's a loop!
So the answer would be "infinity" for this grid.
Time it takes: We visit each cell a few times, so it's fast even for big grids
Memory needed: We store information about each cell and its connections
==================================================================================
*/
#include <bits/stdc++.h>
using namespace std;
// Given a letter, what comes next in the R-B-I-K sequence?
char get_next(char c) {
if (c == 'R') return 'B';
if (c == 'B') return 'I';
if (c == 'I') return 'K';
return 'R'; // K wraps back to R (and we score a point!)
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int rows, cols;
cin >> rows >> cols;
vector<string> grid(rows);
for (int i = 0; i < rows; i++) {
cin >> grid[i];
}
int num_cells = rows * cols;
// We'll treat the grid as one long list of cells
// This helper converts a (row, col) position to a single cell number
auto get_id = [&](int r, int c) {
return r * cols + c;
};
// =============================================================================
// STEP 1: Build a map of where we can move
// =============================================================================
// graph[i] = list of cells we can reach from cell i
vector<vector<int>> graph(num_cells);
// Keep track of all 'R' cells because those are our starting points
vector<int> start_positions;
// Look at every cell in the grid
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
char letter = grid[r][c];
// If this is an 'R', we can start here
if (letter == 'R') {
start_positions.push_back(get_id(r, c));
}
// What letter are we looking for in the next cell?
char next_needed = get_next(letter);
// Check all 4 directions: up, down, left, right
int dr[] = {-1, 1, 0, 0};
int dc[] = {0, 0, -1, 1};
int my_id = get_id(r, c);
for (int d = 0; d < 4; d++) {
int new_r = r + dr[d];
int new_c = c + dc[d];
// Make sure the new position is inside the grid
if (new_r < 0 || new_r >= rows || new_c < 0 || new_c >= cols) {
continue;
}
// Can we move there? Only if it has the letter we need
if (grid[new_r][new_c] == next_needed) {
graph[my_id].push_back(get_id(new_r, new_c));
}
}
}
}
// Now figure out which cells we can actually reach if we start from any 'R'
// We only care about these reachable cells
vector<bool> can_reach(num_cells, false);
queue<int> q;
// Mark all starting 'R' positions as reachable
for (int start : start_positions) {
if (!can_reach[start]) {
can_reach[start] = true;
q.push(start);
}
}
// Spread out from the starting positions, marking everything we can reach
while (!q.empty()) {
int current = q.front();
q.pop();
// Try moving to all neighbors
for (int next : graph[current]) {
if (!can_reach[next]) {
can_reach[next] = true;
q.push(next);
}
}
}
// =============================================================================
// STEP 2: Check if we can walk in circles (cycle detection)
// =============================================================================
// We'll mark each cell with a color as we explore:
// 0 (white) = haven't visited yet
// 1 (gray) = currently exploring paths from this cell
// 2 (black) = finished exploring, no cycles found from here
// If we ever visit a gray cell, it means we came back to where we were → cycle!
vector<int> state(num_cells, 0);
bool has_cycle = false;
// Check every reachable cell for cycles
for (int pos = 0; pos < num_cells && !has_cycle; pos++) {
// Skip cells we can't reach or already finished checking
if (!can_reach[pos] || state[pos] != 0) continue;
// We'll do depth-first search without recursion
// (using a manual stack to avoid crashes on huge grids)
vector<pair<int, int>> stack; // {current_cell, which_neighbor_to_check_next}
stack.push_back({pos, 0});
state[pos] = 1; // Mark as gray (currently exploring)
while (!stack.empty() && !has_cycle) {
int curr = stack.back().first;
int& neighbor_idx = stack.back().second;
// Have we checked all neighbors of this cell?
if (neighbor_idx >= (int)graph[curr].size()) {
state[curr] = 2; // Mark as black (finished)
stack.pop_back();
continue;
}
int next = graph[curr][neighbor_idx++];
// Only look at cells we can reach
if (!can_reach[next]) continue;
if (state[next] == 0) {
// White cell - haven't visited yet, so explore it
state[next] = 1; // Mark as gray
stack.push_back({next, 0});
} else if (state[next] == 1) {
// Gray cell - we're back to a cell we're currently exploring!
// This means we found a cycle
has_cycle = true;
}
// If state[next] == 2 (black), we already fully explored it, so skip
}
}
// If we found a cycle, we can loop forever and score infinite points
if (has_cycle) {
cout << "infinity\n";
return 0;
}
// =============================================================================
// STEP 3: Find the longest path (no cycles, so there's a definite answer)
// =============================================================================
// Strategy: process cells in "topological order"
// This means we always process a cell AFTER we've processed all the cells
// that can lead to it. This way, we know the best score to reach each cell.
// First, count how many paths lead INTO each cell
vector<int> incoming_count(num_cells, 0);
for (int pos = 0; pos < num_cells; pos++) {
if (!can_reach[pos]) continue;
for (int next : graph[pos]) {
if (can_reach[next]) {
incoming_count[next]++;
}
}
}
// Start with cells that have no incoming paths
// (these are cells we can only reach by starting there)
queue<int> process_queue;
for (int pos = 0; pos < num_cells; pos++) {
if (can_reach[pos] && incoming_count[pos] == 0) {
process_queue.push(pos);
}
}
// For each cell, track the best score we can have when we reach it
const int IMPOSSIBLE = -1000000000;
vector<int> best_score(num_cells, IMPOSSIBLE);
// All 'R' cells start with a score of 0
// (we haven't completed any RBIK cycles yet)
for (int start : start_positions) {
if (can_reach[start]) {
best_score[start] = 0;
}
}
int final_answer = 0;
// Process cells one by one in topological order
while (!process_queue.empty()) {
int current = process_queue.front();
process_queue.pop();
// Keep track of the best score we've seen anywhere
if (best_score[current] > final_answer) {
final_answer = best_score[current];
}
// Figure out what letter this cell has
int r = current / cols;
int c = current % cols;
char letter = grid[r][c];
// Try moving to all neighbors
for (int next : graph[current]) {
if (!can_reach[next]) continue;
// Do we score a point for moving from current to next?
// Yes, if we're at a 'K' moving to an 'R' (completing the cycle!)
int points = (letter == 'K') ? 1 : 0;
// Update the neighbor's best score if we found a better path
best_score[next] = max(best_score[next], best_score[current] + points);
// This neighbor has one less incoming path to wait for
incoming_count[next]--;
// If we've processed all paths into this neighbor, it's ready
if (incoming_count[next] == 0) {
process_queue.push(next);
}
}
}
cout << final_answer << "\n";
return 0;
}