矩形场中有镜子,测量N乘以M
正方形(1 <= N,M <= 1,000)。在每个广场,有两倍
两个相对角落之间的双面镜子。这两个可能
配置由/
表示(镜像连接
左下角到右上角)和\
(a
将左上角连接到右下角的镜子。)
考虑将光束射入此广场。您可以沿着网格的某些列或行垂直或水平拍摄光束。 这使得光束基于该布置反射一定数量的反射镜。当一束光照射到镜子上时,因为镜子都是对角线的,所以被反射的垂直光束将开始沿水平方向传播,反之亦然。
可以反射光束的最大镜子数是多少 如果光可以无限反射,答案是-1。因此,给定网格的排列,问题是计算这个最大数
例如: 一个3 x 3的网格,其配置如下:
/\\
\\\
/\/
的输出为:
3
约束:网格最高可达1000 x 1000
你可以通过向中柱发射光束来获得3。
我的解决方案:
从每个可能的位置(所有外边缘位置)拍摄光束。模拟这些光束并在光束射出时完成计数。如果光束再次击中相同位置则输出-1。 我的解决方案仅适用于小型情况,但不适用于网格超过100 x 100的较大情况,需要很长时间才能完成。
我希望将其归结为 O(200万)。
你能建议一些算法来帮助吗?
答案 0 :(得分:0)
我认为您可以将此视为图表问题。镜像在/左上角有一个节点,右下角有一个节点。如果镜像是\,右上角有一个节点,左下角有一个节点。您可以根据镜像设置将这些节点连接到相邻网格点中的节点。这为您提供了一个图表,该图表可能包含许多断开连接的循环或路径,但仍然是图表。
第一个问题 - 图表是否包含任何周期?您可以通过深度优先搜索有效地回答这个问题如果是这样,根据规则的具体情况,您可以通过沿着循环内的列射束来无限地反射光线。
第二个问题 - 最长的路径是什么?您可以使用第一个深度优先搜索将图形拆分为连接的组件,并丢弃包含循环的图形。其余组件将是简单的路径,因此应该很容易计算出它们的长度。有几种方法可以快速为树做到这一点 - 我在搜索中找到的第一个方法是http://www.geeksforgeeks.org/diameter-of-a-binary-tree/
答案 1 :(得分:0)
这听起来像一个有趣的问题。来自@Xavier Holt的文章可能非常重要:“光束永远无法无限期地反射”。旨在跟踪访问字段的每个数据结构(即,检查某个字段是否被访问过两次)可能 - 在最坏的情况下 - 显着减慢整个事情。
mcdowella建议的基于图表的方法在这里是可行的。但是,由于光束如何通过镜子网格移动的规则非常简单(并且如上所述,周期检测等不是必需的),人们可以将其向下煮,通过2D阵列。然后,当前状态由当前位置(x,y)和当前方向(dy,dy)表示,该方向根据遇到的每种镜像类型进行更新。
我刚刚实现了这个(用Java)。 computeResults
方法计算5个元素int[]
数组的列表,其中
“核心逻辑”在simulate
方法中。
某些部分(特别是将字段和解决方案路径渲染到框架中的部分)相当快速。很脏,但也许有人发现它很有趣。在任何情况下,它都会在几秒钟内在一台非常老的PC上计算2000x2000网格的解决方案。
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MirrorTracer
{
public static void main(String[] args)
{
//basicTest();
largerTest();
}
private static void basicTest()
{
String input =
"SBB" +
"BBB" +
"SBS";
int sizeX = 3;
int sizeY = 3;
int array[][] = createArray(input, sizeX, sizeY);
// int n = simulate(array, 2, 0, 0, 1);
// System.out.println(n);
List<int[]> results = computeResults(array, sizeX, sizeY);
printResults(array, sizeX, sizeY, results);
}
private static void largerTest()
{
int sizeX = 60;
int sizeY = 60;
int array[][] = createRandomArray(sizeX, sizeY, new Random(0));
List<int[]> results = computeResults(array, sizeX, sizeY);
printResults(array, sizeX, sizeY, results);
showResult(array, sizeX, sizeY, findBestResult(results));
}
private static List<int[]> computeResults(int array[][], int sizeX, int sizeY)
{
List<int[]> results = new ArrayList<int[]>();
for (int x=1; x<sizeX+1; x++)
{
results.add(compute(array, x, 0, 0, 1));
//results.add(compute(array, x, sizeY+1, 0, -1));
}
for (int y=1; y<sizeY+1; y++)
{
results.add(compute(array, 0, y, 1, 0));
//results.add(compute(array, sizeX+1, y, -1, 0));
}
return results;
}
private static int[] compute(int array[][], int x, int y, int dx, int dy)
{
int nx = x + dx;
int ny = y + dy;
int n = simulate(array, x, y, dx, dy);
return new int[]{ nx-1, ny-1, dx, dy, n };
}
private static int simulate(int array[][], int x, int y, int dx, int dy)
{
int steps = 0;
while (true)
{
int nx = x + dx;
int ny = y + dy;
if (isOnBorder(array, nx, ny))
{
break;
}
//System.out.println("Move from "+x+" "+y+" in "+dx+" "+dy+" to "+nx+" "+ny);
int ndx = dy;
int ndy = dx;
if (array[nx][ny] == '/')
{
ndx = -dy;
ndy = -dx;
}
x = nx;
y = ny;
dx = ndx;
dy = ndy;
steps++;
}
return steps;
}
private static boolean isOnBorder(int array[][], int x, int y)
{
return
x == 0 || x == array.length - 1 ||
y == 0 || y == array[x].length - 1;
}
private static int[][] createArray(String input, int sizeX, int sizeY)
{
int array[][] = new int[sizeX+2][sizeY+2];
for (int y=1; y<sizeY+1; y++)
{
for (int x=1; x<sizeX+1; x++)
{
char c = input.charAt((x-1) + (y-1) * sizeX);
array[x][y] = c == 'S' ? '/' : '\\';
}
}
return array;
}
private static int[][] createRandomArray(
int sizeX, int sizeY, Random random)
{
int array[][] = new int[sizeX+2][sizeY+2];
for (int y=1; y<sizeY+1; y++)
{
for (int x=1; x<sizeX+1; x++)
{
boolean b = random.nextBoolean();
array[x][y] = b ? '/' : '\\';
}
}
return array;
}
private static void printResults(
int array[][], int sizeX, int sizeY, List<int[]> results)
{
print(array, sizeX, sizeY);
for (int result[] : results)
{
printResult(result);
}
int bestResult[] = findBestResult(results);
System.out.println("Longest sequence:");
printResult(bestResult);
}
private static void print(int array[][], int sizeX, int sizeY)
{
for (int y=1; y<sizeY+1; y++)
{
for (int x=1; x<sizeX+1; x++)
{
System.out.print((char)array[x][y]);
}
System.out.println();
}
}
private static int[] findBestResult(List<int[]> results)
{
int maxLength = -1;
int maxLengthResult[] = null;
for (int result[] : results)
{
if (result[4] > maxLength)
{
maxLength = result[4];
maxLengthResult = result;
}
}
return maxLengthResult;
}
private static void printResult(int result[])
{
int x = result[0];
int y = result[1];
int dx = result[2];
int dy = result[3];
int n = result[4];
System.out.println("Entering at "+x+" "+y+" in direction "+dx+" "+dy+" does "+n+" steps");
}
private static void showResult(
final int array[][], final int sizeX, final int sizeY,
final int bestResult[])
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI(array, sizeX, sizeY, bestResult);
}
});
}
private static void createAndShowGUI(
final int array[][], final int sizeX, final int sizeY,
final int bestResult[])
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel resultPanel = new JPanel()
{
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
int cellSizeX = getWidth() / (sizeX+2);
int cellSizeY = getHeight() / (sizeY+2);
g.setColor(Color.BLACK);
for (int y=1; y<sizeY+1; y++)
{
for (int x=1; x<sizeX+1; x++)
{
int x0 = x * cellSizeX;
int y0 = y * cellSizeY;
int x1 = x0 + cellSizeX;
int y1 = y0 + cellSizeY;
if (array[x][y] == '/')
{
g.drawLine(x0+2, y1-2, x1-2, y0+2);
}
else
{
g.drawLine(x0+2, y0+2, x1-2, y1-2);
}
}
}
g.setColor(Color.RED);
int dx = bestResult[2];
int dy = bestResult[3];
int x = bestResult[0]-dx+1;
int y = bestResult[1]-dy+1;
paintSimulation(g, array, x, y, dx, dy, cellSizeX, cellSizeY);
}
private int paintSimulation(
Graphics g, int array[][], int x, int y,
int dx, int dy, int cellSizeX, int cellSizeY)
{
int steps = 0;
while (true)
{
int nx = x + dx;
int ny = y + dy;
int x0 = x * cellSizeX + cellSizeX / 2;
int y0 = y * cellSizeY + cellSizeY / 2;
int x1 = nx * cellSizeX + cellSizeX / 2;
int y1 = ny * cellSizeY + cellSizeY / 2;
g.drawLine(x0, y0, x1, y1);
if (isOnBorder(array, nx, ny))
{
break;
}
int ndx = dy;
int ndy = dx;
if (array[nx][ny] == '/')
{
ndx = -dy;
ndy = -dx;
}
x = nx;
y = ny;
dx = ndx;
dy = ndy;
steps++;
}
return steps;
}
};
f.getContentPane().add(resultPanel);
f.setSize(800,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}