Possible NxN matrices, t 1's in each row and column, none in diagonal?

跟風遠走 提交于 2019-12-07 22:34:09

问题


Background:

  • This is extra credit in a logic and algorithms class, we are currently covering propositional logic, P implies Q that kind of thing, so I think the Prof wanted to give us and assignment out of our depth.

  • I will implement this in C++, but right now I just want to understand whats going on in the example....which I don't.

Example

Enclosed is a walkthrough for the Lefty algorithm which computes the number of nxn 0-1 matrices with t ones in each row and column, but none on the main diagonal. The algorithm used to verify the equations presented counts all the possible matrices, but does not construct them. It is called "Lefty", it is reasonably simple, and is best described with an example. Suppose we wanted to compute the number of 6x6 0-1 matrices with 2 ones in each row and column, but no ones on the main diagonal. We first create a state vector of length 6, filled with 2s:

(2 2 2 2 2 2)

This state vector symbolizes the number of ones we must yet place in each column. We accompany it with an integer which we call the "puck", which is initialized to 1. This puck will increase by one each time we perform a ones placement in a row of the matrix (a "round"), and we will think of the puck as "covering up" the column that we wonít be able to place ones in for that round. Since we are starting with the first row (and hence the first round), we place two ones in any column, but since the puck is 1, we cannot place ones in the first column. This corresponds to the forced zero that we must place in the first column, since the 1,1 entry is part of the matrixís main diagonal. The algorithm will iterate over all possible choices, but to show each round, we shall make a choice, say the 2nd and 6th columns. We then drop the state vector by subtracting 1 from the 2nd and 6th values, and advance the puck:

(2 1 2 2 2 1); 2

For the second round, the puck is 2, so we cannot place a one in that column. We choose to place ones in the 4th and 6th columns instead and advance the puck:

(2 1 2 1 2 0); 3

Now at this point, we can place two ones anywhere but the 3rd and 6th columns. At this stage the algorithm treats the possibilities di§erently: We can place some ones before the puck (in the column indexes less than the puck value), and/or some ones after the puck (in the column indexes greater than the puck value). Before the puck, we can place a one where there is a 1, or where there is a 2; after the puck, we can place a one in the 4th or 5th columns. Suppose we place ones in the 4th and 5th columns. We drop the state vector and advance the puck once more:

(2 1 2 0 1 0); 4

1 For the 4th round, we once again notice we can place some ones before the puck, and/or some ones after. Before the puck, we can place:

(a) two ones in columns of value 2 (1 choice)

(b) one one in the column of value 2 (2 choices)

(c) one one in the column of value 1 (1 choice)

(d) one one in a column of value 2 and one one in a column of value 1 (2 choices).

After we choose one of the options (a)-(d), we must multiply the listed number of choices by one for each way to place any remaining ones to the right of the puck. So, for option (a), there is only one way to place the ones. For option (b), there are two possible ways for each possible placement of the remaining one to the right of the puck. Since there is only one nonzero value remaining to the right of the puck, there are two ways total. For option (c), there is one possible way for each possible placement of the remaining one to the right of the puck. Again, since there is only one nonzero value remaining, there is one way total. For option (d), there are two possible ways to place the ones. We choose option (a). We drop the state vector and advance the puck:

(1 1 1 0 1 0); 5

Since the puck is "covering" the 1 in the 5th column, we can only place ones before the puck. There are (3 take 2) ways to place two ones in the three columns of value 1, so we multiply 3 by the number of ways to get remaining possibilities. After choosing the 1st and 3rd columns (though it doesnít matter since weíre left of the puck; any two of the three will do), we drop the state vector and advance the puck one final time:

(0 1 0 0 1 0); 6

There is only one way to place the ones in this situation, so we terminate with a count of 1. But we must take into account all the multiplications along the way: 1*1*1*1*3*1 = 3.

Another way of thinking of the varying row is to start with the first matrix, focus on the lower-left 2x3 submatrix, and note how many ways there were to permute the columns of that submatrix. Since there are only 3 such ways, we get 3 matrices.

What I think I understand

  • This algorithm counts the the all possible 6x6 arrays with 2 1's in each row and column with none in the descending diagonal.

  • Instead of constructing the matrices it uses a "state_vector" filled with 6 2's, representing how many 2's are in that column, and a "puck" that represents the index of the diagonal and the current row as the algorithm iterates.

What I don't understand

  • The algorithm comes up with a value of 1 for each row except 5 which is assigned a 3, at the end these values are multiplied for the end result. These values are supposed to be the possible placements for each row but there are many possibilities for row 1, why was it given a one, why did the algorithm wait until row 5 to figure all the possible permutations?

    Any help will be much appreciated!


回答1:


I think what is going on is a tradeoff between doing combinatorics and doing recursion.

The algorithm is using recursion to add up all the counts for each choice of placing the 1's. The example considers a single choice at each stage, but to get the full count it needs to add the results for all possible choices.

Now it is quite possible to get the final answer simply using recursion all the way down. Every time we reach the bottom we just add 1 to the total count.

The normal next step is to cache the result of calling the recursive function as this greatly improves the speed. However, the memory use for such a dynamic programming approach depends on the number of states that need to be expanded.

The combinatorics in the later stages is making use of the fact that once the puck has passed a column, the exact arrangement of counts in the columns doesn't matter so you only need to evaluate one representative of each type and then add up the resulting counts multiplied by the number of equivalent ways.

This both reduces the memory use and improves the speed of the algorithm.

Note that you cannot use combinatorics for counts to the right of the puck, as for these the order of the counts is still important due to the restriction about the diagonal.

P.S. You can actually compute the number of ways for counting the number of n*n matrices with 2 1's in each column (and no diagonal entries) with pure combinatorics as:

a(n) = Sum_{k=0..n} Sum_{s=0..k} Sum_{j=0..n-k} (-1)^(k+j-s)*n!*(n-k)!*(2n-k-2j-s)!/(s!*(k-s)!*(n-k-j)!^2*j!*2^(2n-2k-j))

According to OEIS.



来源:https://stackoverflow.com/questions/34830930/possible-nxn-matrices-t-1s-in-each-row-and-column-none-in-diagonal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!