我真的遇到了这个问题。
在这个问题中,您将获得一个2xN的电路板。您需要以这样的方式在此板中填写非负数:
考虑到数字N,可以通过多少种方式完成? 如果电路板中有一个具有不同数字的单元,则认为两种方式不同。
输出应该是矩阵可以形成的方式的数量。 矩阵可以具有重复数字并且可以使用零。矩阵不应该有增加的数字,但是可以相互并排填充相等的数字。
示例:
输入 - > 5
输出 - > 16
答案 0 :(得分:3)
从你的例子(input = 5,output = 16)我想只允许整数。
一种天真(强力)解决方案是使用回溯算法:
http://en.wikipedia.org/wiki/Backtracking
在此网站上,您可以看到填充数独板的示例,直到找到解决方案。
==
例如:
您有大小为2N的整数数组。
For position 0 you take first free number.
If solution is not broken yet you go to position 1 of array.
If solution is broken - stop as cannot back anymore
For position 1 you take next free number.
If solution is not broken you you go to position 2 of array.
If solution is broken you back to previous sten and take next free number.
For position 2...
这通常通过递归来完成。 我认为,在每个位置(递归级别),数字可以从池0..N。
中获取尝试 - 祝你好运。
修改强>
这是有效的解决方案(使用回溯算法):
private final int N = 5;
// 2 rows in one array [0..N-1, N..2N-1]
private int[] board = new int[2 * N];
// found solution counter
int found = 0;
/*
* this method set next number to current position
* and recursively go to next position.
*/
public void check(int position) {
// if board is complete - check if valid
if (position == 2 * N) {
if (isValid()) {
System.out.println("foun : " + Arrays.toString(board));
found++;
}
return;
}
// if board is not complete - put all numbers (0..N) into current position
// and recursively go to next position
for (int v = 0; v <= N; v++) {
board[position] = v;
// if solution is already broken - step backwards
// see: backtracking algorithms
if (isBroken(position)) {
return;
}
check(position + 1);
}
}
public boolean isValid() {
// condition 1
int sum = 0;
for (int i = 0; i < board.length; i++) {
sum += board[i];
}
if (sum != N) {
return false;
}
// conditin 2
int prev = board[0];
for (int i = 1; i < N; i++) {
if (board[i] > prev) {
return false;
}
prev = board[i];
}
prev = board[N];
for (int i = N + 1; i < 2 * N; i++) {
if (board[i] > prev) {
return false;
}
prev = board[i];
}
// condition 3
for (int i = 0; i < N; i++) {
int top = board[i];
int bottom = board[i + N];
if (top < bottom) {
return false;
}
}
// valid
return true;
}
// simplified version of this method - but correct
public boolean isBroken(int current) {
int sum = 0;
for (int i = 0; i <= current; i++) {
sum += board[i];
}
return sum > N;
}
public void start() {
check(0);
System.out.println("found: " + found);
}
N = 5的程序输出:
found : [1, 1, 1, 0, 0, 1, 1, 0, 0, 0]
found : [1, 1, 1, 1, 0, 1, 0, 0, 0, 0]
found : [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
found : [2, 1, 0, 0, 0, 1, 1, 0, 0, 0]
found : [2, 1, 0, 0, 0, 2, 0, 0, 0, 0]
found : [2, 1, 1, 0, 0, 1, 0, 0, 0, 0]
found : [2, 1, 1, 1, 0, 0, 0, 0, 0, 0]
found : [2, 2, 0, 0, 0, 1, 0, 0, 0, 0]
found : [2, 2, 1, 0, 0, 0, 0, 0, 0, 0]
found : [3, 0, 0, 0, 0, 2, 0, 0, 0, 0]
found : [3, 1, 0, 0, 0, 1, 0, 0, 0, 0]
found : [3, 1, 1, 0, 0, 0, 0, 0, 0, 0]
found : [3, 2, 0, 0, 0, 0, 0, 0, 0, 0]
found : [4, 0, 0, 0, 0, 1, 0, 0, 0, 0]
found : [4, 1, 0, 0, 0, 0, 0, 0, 0, 0]
found : [5, 0, 0, 0, 0, 0, 0, 0, 0, 0]
found: 16
答案 1 :(得分:0)
这里有一种强力方式:因为这是一个2xN矩阵,并且所有数字之和必须为N,最简单的解决方案是用1&#39; s填充第一行,用0&填充第2行#39; S。现在你需要一个递归算法,它采用一个有效的板,并从任何&#34; free&#34;中删除1。职位并将其添加到任何法律职位。该板也是一个解决方案。通过&#34;免费&#34;我的意思是位置[i,j]的数字n,其中[i + 1,j]&lt; = n - 1和[i,j + 1]&lt; = n - 1.然后你递归地调用新的算法董事会,并保存一切。
剩下的就是重复数据删除解决方案。
输入5的算法示例: 初步解决方案:
11111
00000
唯一的#34;免费&#34;数字是[0,4]。删除1,唯一的合法位置是[0,0]和[0,1]。这为您提供了2个新解决方案
21110
00000
和
11110
10000
现在再次对这两种解决方案应用相同的算法。请注意,第二块板现在有2&#34; free&#34;数字。重复,直到你到达 p>
50000
00000
编辑:这个例子编写了很多乐趣。没有对它进行测试,但那是我的头脑所在:
public void TwoRowBoard()
{
var board = new int[2, N];
//Create initial, simplest solution.
for (int i = 0; i < N; i++)
{
board[0, i] = 1;
}
var solutions = new List<int[,]>();
RecursiveSolve(board, solutions);
}
private void RecursiveSolve(int[,] board, List<int[,]> solutions)
{
var freeNumbers = GetFreeNumbers(board);
foreach (var freeNumber in freeNumbers)
{
board[freeNumber.i, freeNumber.j] -= 1;
var legalPositions = GetLegalPositions(board);
foreach (var legalPosition in legalPositions)
{
var newBoard = Copy(board);
newBoard[legalPosition.i, legalPosition.j] += 1;
solutions.Add(newBoard);
RecursiveSolve(newBoard, solutions);
}
}
}
private List<Coordinates> GetLegalPositions(int[,] board)
{
//Position 0, 0 is always legal.
var results = new List<Coordinates> {new Coordinates {i = 0, j = 0}};
//Row 0
for (int j = 1; j < N; j++)
{
if (board[0, j - 1] > board[0, j])
{
results.Add(new Coordinates{i = 0, j = j});
}
}
//Row 1. Board[1, higher than N/2] are never legal positions.
for (int j = 0; j <= N /2; j++)
{
if (board[1, j - 1] > board[1, j]
&& board[0, j] > board[1, j])
{
results.Add(new Coordinates{i = 1, j = j});
}
}
return results;
}
private List<Coordinates> GetFreeNumbers(int[,] board)
{
var results = new List<Coordinates>();
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < N; j++)
{
if (i == 0 && j == 0)
{
continue;
}
if (i == 0)
{
if (j == N - 1 && board[0, j] > 0)
{
results.Add(new Coordinates {i = 0, j = j});
}
else if (board[0, j] > board[1, j]
&& board[0, j] > board[0, j + 1])
{
results.Add(new Coordinates {i = 0, j = j});
}
}
else
{
if (j > N/2 && board[1, j] > 0)
{
throw new Exception("Don't see how it's possible for board[1, N/2 or higher] to not be 0");
}
if (board[1, j] > board[1, j + 1])
{
results.Add(new Coordinates{i = 1, j = j});
}
}
}
}
return results;
}
public class Coordinates
{
public int i { get; set; }
public int j { get; set; }
}
答案 2 :(得分:0)
我几乎肯定这有封闭形式的解决方案,或类似于封闭形式的解决方案的另一个问题。我会以递归方式进行编程。
所以假设你知道N的解决方案。你想要N + 1。所以你应该做的是采取N的所有解决方案,看看你可以在哪里坚持额外的1,而不会破坏任何限制。也就是说,超级将N个解决方案强加在N + 1板上然后尝试在所有2N个位置添加1而不破坏约束。然后将它们全部存储在一个集合中,这样它们就会被删除。
无论如何,它与http://en.wikipedia.org/wiki/Partition_(number_theory)
类似