Breadth first search: Knight cover - algorithm

I'm trying to follow the USACO training course on algorithms (http://ace.delos.com/usacogate) - and I am currently at a page that describes DFS, BFS etc. I do understand these concepts, but the sample problem they've given for BFS - knight cover - has me puzzled. Here's the problem statement:
Place as few knights as possible on an n x n chess board so that every square is attacked. A knight is not considered to attack the square on which it sits.
This is BFS, the page says, since it tries to see if there's a solution with n knights before trying n+1 knights - which is pretty clear.
However, I don't understand how to formulate the solution from this alone. Can someone help me with the pseudocode for this?
Thanks much in advance!

It is BFS, but you don't search the chessboard; search the space of placements:
Initial state: no knight is placed
Valid move: place a knight on any unoccupied tile
Goal state: all tiles are either occupied or attacked
basic algorithm (BFS of the state space):
push the initial state to the BFS queue.
while there is something in the queue:
remove one state from the queue.
for every unoccupied tile:
create a copy of the current state.
add one knight to that tile.
if the new state doesn't exist in the queue:
if the new state is a goal state, finish.
else add it to the queue.
Note that I'm assuming that all paths to a state are of the same length. This is true when looking for a set of placements this way, but it is not true in general. In cases where this is not true, you should store the set of all visited nodes to avoid revisiting already explored states.
You may require the knights be added left-to-right, top-to-bottom. Then you don't need to check for duplicates in the queue. Additionally, you may discard a state early if you know that an unattacked tile cannot be attacked without violating the insertion order.
If you don't do this and leave the duplicate check as well, the algorithm will still produce correct results, but it will do so much slower. 40 000 times slower, approximately (8!=40 320 is the number of duplicates of an 8-knight state).
If you want a faster algorithm, look into A*. Here, one possible heuristic is:
count the number of unattacked and unoccupied tiles
divide the count by nine, rounding up (a knight cannot attack more than eight new tiles or occupy more than one)
the distance (number of knights needed to be added) is no more than this number.
A better heuristic would note the fact that a knight can only attack tiles of the same color, and occupy a tile of the opposite color. This may improve the previous heuristic slightly (but still potentially help a lot).
A better heuristic should be able to exploit the fact that a knight can cover free spots in no more than a 5x5 square. A heuristic should compute fast, but this may help when there are few spots to cover.
Technical details:
You may represent each state as a 64-bit bit-mask. While this requires some bitwise manipulation, it really helps memory, and equality checking of 64-bit numbers is fast. If you can't have a 64-bit number, use two 32-bit numbers - these should be available.
Circular array queue is efficient, and it's not that hard to expand its capacity. If you have to implement your own queue, pick this one.

Here is an implementation in C++.
It just uses the basic brute force, so it is only good only till n = 5.
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
bool isFinal(vector<vector<bool> >& board, int n)
{
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(!board[i][j])
return false;
}
}
return true;
}
void printBoard(vector<pair<int,int> > vec, int n)
{
vector<string> printIt(n);
for(int i = 0; i < n; ++i)
{
string s = "";
for(int j = 0; j < n; ++j)
{
s += ".";
}
printIt[i] = s;
}
int m = vec.size();
for(int i = 0; i < m; ++i)
{
printIt[vec[i].first][vec[i].second] = 'x';
}
for(int i = 0; i < n; ++i)
{
cout << printIt[i] << endl;
}
cout << endl;
}
void updateBoard(vector<vector<bool> >& board, int i, int j, int n)
{
board[i][j] = true;
if(i-2 >= 0 && j+1 < n)
board[i-2][j+1] = true;
if(i-1 >= 0 && j+2 < n)
board[i-1][j+2] = true;
if(i+1 < n && j+2 < n)
board[i+1][j+2] = true;
if(i+2 < n && j+1 < n)
board[i+2][j+1] = true;
if(i-2 >= 0 && j-1 >= 0)
board[i-2][j-1] = true;
if(i-1 >= 0 && j-2 >= 0)
board[i-1][j-2] = true;
if(i+1 < n && j-2 >= 0)
board[i+1][j-2] = true;
if(i+2 < n && j-1 >= 0)
board[i+2][j-1] = true;
}
bool isThere(vector<pair<int,int> >& vec, vector<vector<pair<int,int> > >& setOfBoards, int len)
{
for(int i = 0; i < len; ++i)
{
if(setOfBoards[i] == vec)
return true;
}
return false;
}
int main()
{
int n;
cin >> n;
vector<vector<pair<int,int> > > setOfBoards;
int len = 0;
vector<vector<bool> > startingBoard(n);
for(int i = 0; i < n; ++i)
{
vector<bool> vec(n,0);
startingBoard[i] = vec;
}
vector<pair<int,int> > startingVec;
vector<vector<vector<vector<bool> > > > q1;
vector<vector<vector<pair<int,int> > > > q2;
vector<vector<vector<bool> > > sLayer1;
vector<vector<pair<int,int> > > sLayer2;
sLayer1.push_back(startingBoard);
sLayer2.push_back(startingVec);
q1.push_back(sLayer1);
q2.push_back(sLayer2);
int k = 0;
bool flag = false;
int count = 0;
while(!flag && !q1[k].empty())
{
int m = q1[k].size();
vector<vector<vector<bool> > > layer1;
vector<vector<pair<int,int> > > layer2;
q1.push_back(layer1);
q2.push_back(layer2);
for(int l = 0; l < m; ++l)
{
vector<vector<bool> > board = q1[k][l];
vector<pair<int,int> > vec = q2[k][l];
if(isFinal(board, n))
{
while(l < m)
{
board = q1[k][l];
vec = q2[k][l];
if(isFinal(board, n))
{
printBoard(vec, n);
++count;
}
++l;
}
flag = true;
break;
}
for(int i = 0; i < n; ++i)
{
for(int j = 0; j < n; ++j)
{
if(!board[i][j])
{
pair<int,int> p;
p.first = i;
p.second = j;
vector<vector<bool> > newBoard = board;
vector<pair<int,int> > newVec = vec;
newVec.push_back(p);
updateBoard(newBoard, i, j, n);
sort(newVec.begin(), newVec.end());
if(!isThere(newVec, setOfBoards, len))
{
q1[k+1].push_back(newBoard);
q2[k+1].push_back(newVec);
setOfBoards.push_back(newVec);
++len;
}
}
}
}
}
++k;
}
cout << count << endl;
}

Related

Maximum subArray product using Divide and Conquer Anyone?

I am aware that this is one of the most common coding questions when it comes to integral arrays. I am looking for a solution to the problem of finding the longest contiguous subArray product within the array, but using a Divide and Conquer approach.
I split my input array into two halves: the left and right arrays are solved recursively in case the solution falls entirely in the half array. Where I have a problem is with the scenario where the subArray crosses the mid-point of the array. Here is a short snippet of my code for the function handling the crossing:
pair<int,pair<int, int>> maxMidCrossing(vector<int>& nums, int low, int mid, int high)
{
int m = 1;
int leftIndx = low;
long long leftProduct = INT_MIN;
for(int i = mid-1; i>= low; --i)
{
m *= nums[i];
if(m > leftProduct) {
leftProduct = m;
leftIndx = i;
}
}
int mleft = m;
m=1;
int rightIndx = high;
long long rightProduct = INT_MIN;
for(int i = mid; i<= high; ++i)
{
m *= nums[i];
if(m > rightProduct) {
rightProduct = m;
rightIndx = i;
}
}
int mright = m;
cout << "\nRight product " << rightProduct;
pair<int, int> tmp;
int maximum = 0;
// Check the multiplication of both sides of the array to see if the combined subarray satisfies the maximum product condition.
if(mleft*mright < leftProduct*rightProduct) {
tmp = pair(leftIndx, rightIndx);
maximum = leftProduct*rightProduct;
}
else {
tmp = pair(low, high);
maximum = mleft*mright;
}
return pair(maximum, tmp);
}
The function handling the entire search contains the following:
auto leftIndx = indexProduct(left);
auto rightIndx = indexProduct(right);
auto midResult = maxMidCrossing(nums, 0, mid, nums.size()-1); // middle crossing
//.....more code........
if(mLeft > midProduct && mLeft > mRight)
tmp=leftIndx;
else if (mRight > midProduct && mRight > mLeft)
tmp = pair(rightIndx.first + mid, rightIndx.second + mid);
else tmp=midIndx;
In the end, I just compute the maximum product across the 3 scenarios: left array, crossing array, right array.
I still have a few corner cases failing. My question is if this problem admits a recursive solution of the Divide and Conquer type, and if anyone can spot what I may be doing wrong in my code, I would appreciate any hints that could help me get unstuck.
Thanks,
Amine
Take a look at these from leetcode
C++ Divide and Conquer
https://leetcode.com/problems/maximum-product-subarray/discuss/48289/c++-divide-and-conquer-solution-8ms
Java
https://leetcode.com/problems/maximum-product-subarray/discuss/367839/java-divide-and-conquer-2ms
c#
https://leetcode.com/problems/maximum-product-subarray/discuss/367839/java-divide-and-conquer-2ms

Develop an algorithm

I participated in a programming competition at my University. I solved all the questions except this one. Now I am practicing this question to improve my skills. But I can't figure out the algorithm. If there is any algorithm existing please update me. Or any similar algorithm is present then please tell me I will change it according to this question.
This is what I want to do.
The First line of input is the distance between two points.
After that, each subsequent line contains a pair of numbers indicating the length of cable and quantity of that cable. These cables are used to join the two points.
Input is terminated by 0 0
Output:
The output should contain a single integer representing the minimum number of joints possible to build the requested length of cableway. If no solution possible than print "No solution".
Sample Input
444
16 2
3 2
2 2
30 3
50 10
45 12
8 12
0 0
Sample Output
10
Thanks guys. I found a solution from "Perfect subset Sum" problem and then made a few changes in it. Here's the code.
#include <bits/stdc++.h>
using namespace std;
bool dp[100][100];
int sizeOfJoints = -1;
void display(const vector<int>& v)
{
if (sizeOfJoints == -1)
{
sizeOfJoints = v.size() - 1;
}
else if (v.size()< sizeOfJoints)
{
sizeOfJoints = v.size() - 1;
}
}
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
void printSubsetsRec(int arr[], int i, int sum, vector<int>& p)
{
// If sum becomes 0
if (sum == 0)
{
display(p);
return;
}
if(i<=0 || sum<0)
return;
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
//vector<int> b = p;
printSubsetsRec(arr, i-1, sum, p);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i-1] && dp[i-1][sum-arr[i-1]])
{
p.push_back(arr[i-1]);
printSubsetsRec(arr, i-1, sum-arr[i-1], p);
p.pop_back();
}
}
// all subsets of arr[0..n-1] with sum 0.
void printAllSubsets(int arr[], int n, int sum)
{
if (n == 0 || sum < 0)
return;
// If sum is 0, then answer is true
for (int i = 0; i <= n; i++)
dp[i][0] = true;
// If sum is not 0 and set is empty, then answer is false
for (int i = 1; i <= sum; i++)
dp[0][i] = false;
// Fill the subset table in botton up manner
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
if(j<arr[i-1])
dp[i][j] = dp[i-1][j];
if (j >= arr[i-1])
dp[i][j] = dp[i-1][j] ||
dp[i - 1][j-arr[i-1]];
}
}
if (dp[n][sum] == false)
{
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
vector<int> p;
printSubsetsRec(arr, n, sum, p);
}
// Driver code
int main()
{
int input[2000];
int inputIndex = 0;
int i = 0;
int distance = 0;
cout<< "Enter Input: " <<endl;
cin>> distance;
while(true)
{
int temp1 = 0;
int temp2 = 0;
cin>> temp1;
cin>> temp2;
if (temp1 == 0 && temp2 == 0)
{
break;
}
for (i = 0; i < temp2; i++)
input[inputIndex++] = temp1;
}
cout<< "Processing output. Please wait: " <<endl;
printAllSubsets(input, inputIndex, distance);
if(sizeOfJoints != -1)
cout<<sizeOfJoints;
else
cout<<"No Solution Possible";
return 0;
}

Google Foobar, maximum unique visits under a resource limit, negative weights in graph

I'm having trouble figuring out the type of problem this is. I'm still a student and haven't taken a graph theory/linear optimization class yet.
The only thing I know for sure is to check for negative cycles, as this means you can rack the resource limit up to infinity, allowing for you to pick up each rabbit. I don't know the "reason" to pick the next path. I also don't know when to terminate, as you could keep using all of the edges and make the resource limit drop below 0 forever, but never escape.
I'm not really looking for code (as this is a coding challenge), only the type of problem this is (Ex: Max Flow, Longest Path, Shortest Path, etc.) If you an algorithm that fits this already that would be extra awesome. Thanks.
The time it takes to move from your starting point to all of the bunnies and to the bulkhead will be given to you in a square matrix of integers. Each row will tell you the time it takes to get to the start, first bunny, second bunny, ..., last bunny, and the bulkhead in that order. The order of the rows follows the same pattern (start, each bunny, bulkhead). The bunnies can jump into your arms, so picking them up is instantaneous, and arriving at the bulkhead at the same time as it seals still allows for a successful, if dramatic, escape. (Don't worry, any bunnies you don't pick up will be able to escape with you since they no longer have to carry the ones you did pick up.) You can revisit different spots if you wish, and moving to the bulkhead doesn't mean you have to immediately leave - you can move to and from the bulkhead to pick up additional bunnies if time permits.
In addition to spending time traveling between bunnies, some paths interact with the space station's security checkpoints and add time back to the clock. Adding time to the clock will delay the closing of the bulkhead doors, and if the time goes back up to 0 or a positive number after the doors have already closed, it triggers the bulkhead to reopen. Therefore, it might be possible to walk in a circle and keep gaining time: that is, each time a path is traversed, the same amount of time is used or added.
Write a function of the form answer(times, time_limit) to calculate the most bunnies you can pick up and which bunnies they are, while still escaping through the bulkhead before the doors close for good. If there are multiple sets of bunnies of the same size, return the set of bunnies with the lowest prisoner IDs (as indexes) in sorted order. The bunnies are represented as a sorted list by prisoner ID, with the first bunny being 0. There are at most 5 bunnies, and time_limit is a non-negative integer that is at most 999.
It's a planning problem, basically. The generic approach to planning is to identify the possible states of the world, the initial state, transitions between states, and the final states. Then search the graph that this data imply, most simply using breadth-first search.
For this problem, the relevant state is (1) how much time is left (2) which rabbits we've picked up (3) where we are right now. This means 1,000 clock settings (I'll talk about added time in a minute) times 2^5 = 32 subsets of bunnies times 7 positions = 224,000 possible states, which is a lot for a human but not a computer.
We can deal with added time by swiping a trick from Johnson's algorithm. As Tymur suggests in a comment, run Bellman--Ford and either find a negative cycle (in which case all rabbits can be saved by running around the negative cycle enough times first) or potentials that, when applied, make all times nonnegative. Don't forget to adjust the starting time by the difference in potential between the starting position and the bulkhead.
There you go. I started Google Foobar yesterday. I'll be starting Level 5 shortly. This was my 2nd problem here at level 4. The solution is fast enough as I tried memoizing the states without using the utils class. Anyway, loved the experience. This was by far the best problem solved by me since I got to use Floyd-Warshall(to find the negative cycle if it exists), Bellman-Ford(as a utility function to the weight readjustment step used popularly in algorithms like Johnson's and Suurballe's), Johnson(weight readjustment!), DFS(for recursing over steps) and even memoization using a self-designed hashing function :)
Happy Coding!!
public class Solution
{
public static final int INF = 100000000;
public static final int MEMO_SIZE = 10000;
public static int[] lookup;
public static int[] lookup_for_bunnies;
public static int getHashValue(int[] state, int loc)
{
int hashval = 0;
for(int i = 0; i < state.length; i++)
hashval += state[i] * (1 << i);
hashval += (1 << loc) * 100;
return hashval % MEMO_SIZE;
}
public static boolean findNegativeCycle(int[][] times)
{
int i, j, k;
int checkSum = 0;
int V = times.length;
int[][] graph = new int[V][V];
for(i = 0; i < V; i++)
for(j = 0; j < V; j++)
{
graph[i][j] = times[i][j];
checkSum += times[i][j];
}
if(checkSum == 0)
return true;
for(k = 0; k < V; k++)
for(i = 0; i < V; i++)
for(j = 0; j < V; j++)
if(graph[i][j] > graph[i][k] + graph[k][j])
graph[i][j] = graph[i][k] + graph[k][j];
for(i = 0; i < V; i++)
if(graph[i][i] < 0)
return true;
return false;
}
public static void dfs(int[][] times, int[] state, int loc, int tm, int[] res)
{
int V = times.length;
if(loc == V - 1)
{
int rescued = countArr(state);
int maxRescued = countArr(res);
if(maxRescued < rescued)
for(int i = 0; i < V; i++)
res[i] = state[i];
if(rescued == V - 2)
return;
}
else if(loc > 0)
state[loc] = 1;
int hashval = getHashValue(state, loc);
if(tm < lookup[hashval])
return;
else if(tm == lookup[hashval] && countArr(state) <= lookup_for_bunnies[loc])
return;
else
{
lookup_for_bunnies[loc] = countArr(state);
lookup[hashval] = tm;
for(int i = 0; i < V; i++)
{
if(i != loc && (tm - times[loc][i]) >= 0)
{
boolean stateCache = state[i] == 1;
dfs(times, state, i, tm - times[loc][i], res);
if(stateCache)
state[i] = 1;
else
state[i] = 0;
}
}
}
}
public static int countArr(int[] arr)
{
int counter = 0;
for(int i = 0; i < arr.length; i++)
if(arr[i] == 1)
counter++;
return counter;
}
public static int bellmanFord(int[][] adj, int times_limit)
{
int V = adj.length;
int i, j, k;
int[][] graph = new int[V + 1][V + 1];
for(i = 1; i <= V; i++)
graph[i][0] = INF;
for(i = 0; i < V; i++)
for(j = 0; j < V; j++)
graph[i + 1][j + 1] = adj[i][j];
int[] distance = new int[V + 1] ;
for(i = 1; i <= V; i++)
distance[i] = INF;
for(i = 1; i <= V; i++)
for(j = 0; j <= V; j++)
{
int minDist = INF;
for(k = 0; k <= V; k++)
if(graph[k][j] != INF)
minDist = Math.min(minDist, distance[k] + graph[k][j]);
distance[j] = Math.min(distance[j], minDist);
}
for(i = 0; i < V; i++)
for(j = 0; j < V; j++)
adj[i][j] += distance[i + 1] - distance[j + 1];
return times_limit + distance[1] - distance[V];
}
public static int[] solution(int[][] times, int times_limit)
{
int V = times.length;
if(V == 2)
return new int[]{};
if(findNegativeCycle(times))
{
int ans[] = new int[times.length - 2];
for(int i = 0; i < ans.length; i++)
ans[i] = i;
return ans;
}
lookup = new int[MEMO_SIZE];
lookup_for_bunnies = new int[V];
for(int i = 0; i < V; i++)
lookup_for_bunnies[i] = -1;
times_limit = bellmanFord(times, times_limit);
int initial[] = new int[V];
int res[] = new int[V];
dfs(times, initial, 0, times_limit, res);
int len = countArr(res);
int ans[] = new int[len];
int counter = 0;
for(int i = 0; i < res.length; i++)
if(res[i] == 1)
{
ans[counter++] = i - 1;
if(counter == len)
break;
}
return ans;
}
}

Counting tilings of a rectangle

I am trying to solve this problem but I can't find a solution:
A board consisting of squares arranged into N rows and M columns is given. A tiling of this board is a pattern of tiles that covers it. A tiling is interesting if:
only tiles of size 1x1 and/or 2x2 are used;
each tile of size 1x1 covers exactly one whole square;
each tile of size 2x2 covers exactly four whole squares;
each square of the board is covered by exactly one tile.
For example, the following images show a few interesting tilings of a board of size 4 rows and 3 columns:
http://dabi.altervista.org/images/task.img.4x3_tilings_example.gif
Two interesting tilings of a board are different if there exists at least one square on the board that is covered with a tile of size 1x1 in one tiling and with a tile of size 2x2 in the other. For example, all tilings shown in the images above are different.
Write a function
int count_tilings(int N, int M);
that, given two integers N and M, returns the remainder modulo 10,000,007 of the number of different interesting tilings of a board of size N rows and M columns.
Assume that:
N is an integer within the range [1..1,000,000];
M is an integer within the range [1..7].
For example, given N = 4 and M = 3, the function should return 11, because there are 11 different interesting tilings of a board of size 4 rows and 3 columns:
http://dabi.altervista.org/images/task.img.4x3_tilings_all.gif
for (4,3) the result is 11, for (6,5) the result is 1213.
I tried the following but it doesn't work:
static public int count_tilings ( int N,int M ) {
int result=1;
if ((N==1)||(M==1)) return 1;
result=result+(N-1)*(M-1);
int max_tiling= (int) ((int)(Math.ceil(N/2))*(Math.ceil(M/2)));
System.out.println(max_tiling);
for (int i=2; i<=(max_tiling);i++){
if (N>=2*i){
int n=i+(N-i);
int k=i;
//System.out.println("M-1->"+(M-1) +"i->"+i);
System.out.println("(M-1)^i)->"+(Math.pow((M-1),i)));
System.out.println( "n="+n+ " k="+k);
System.out.println(combinations(n, k));
if (N-i*2>0){
result+= Math.pow((M-1),i)*combinations(n, k);
}else{
result+= Math.pow((M-1),i);
}
}
if (M>=2*i){
int n=i+(M-i);
int k=i;
System.out.println("(N-1)^i)->"+(Math.pow((N-1),i)));
System.out.println( "n="+n+ " k="+k);
System.out.println(combinations(n, k));
if (M-i*2>0){
result+= Math.pow((N-1),i)*combinations(n, k);
}else{
result+= Math.pow((N-1),i);
}
}
}
return result;
}
static long combinations(int n, int k) {
/*binomial coefficient*/
long coeff = 1;
for (int i = n - k + 1; i <= n; i++) {
coeff *= i;
}
for (int i = 1; i <= k; i++) {
coeff /= i;
}
return coeff;
}
Since this is homework I won't give a full solution, but I'll give you some hints.
First here's a recursive solution:
class Program
{
// Important note:
// The value of masks given here is hard-coded for m == 5.
// In a complete solution, you need to calculate the masks for the
// actual value of m given. See explanation in answer for more details.
int[] masks = { 0, 3, 6, 12, 15, 24, 27, 30 };
int CountTilings(int n, int m, int s = 0)
{
if (n == 1) { return 1; }
int result = 0;
foreach (int mask in masks)
{
if ((mask & s) == 0)
{
result += CountTilings(n - 1, m, mask);
}
}
return result;
}
public static void Main()
{
Program p = new Program();
int result = p.CountTilings(6, 5);
Console.WriteLine(result);
}
}
See it working online: ideone
Note that I've added an extra parameter s. This stores the contents of the first column. If the first column is empty, s = 0. If the first column contains some filled squares the corresponding bits in s are set. Initially s = 0, but when a 2 x 2 tile is placed, this fills up some squares in the next column, and that will mean that s will be non-zero in the recursive call.
The masks variable is hard-coded but in a complete solution it needs to be calculated based on the actual value of m. The values stored in masks make more sense if you look at their binary representations:
00000
00011
00110
01100
01111
11000
11011
11110
In other words, it's all the ways of setting pairs of bits in a binary number with m bits. You can write some code to generate all these possiblities. Or since there are only 7 possible values of m, you could also just hard-code all seven possibilities for masks.
There are however two serious problems with the recursive solution.
It will overflow the stack for large values of N.
It requires exponential time to calculate. It is incredibly slow even for small values of N
Both these problems can be solved by rewriting the algorithm to be iterative. Keep m constant and initalize the result for n = 1 for all possible values of s to be 1. This is because if you only have one column you must use only 1x1 tiles, and there is only one way to do this.
Now you can calculate n = 2 for all possible values of s by using the results from n = 1. This can be repeated until you reach n = N. This algorithm completes in linear time with respect to N, and requires constant space.
Here is a recursive solution:
// time used : 27 min
#include <set>
#include <vector>
#include <iostream>
using namespace std;
void placement(int n, set< vector <int> > & p){
for (int i = 0; i < n -1 ; i ++){
for (set<vector<int> > :: iterator j = p.begin(); j != p.end(); j ++){
vector <int> temp = *j;
if (temp[i] == 1 || temp[i+1] == 1) continue;
temp[i] = 1; temp[i+1] = 1;
p.insert(temp);
}
}
}
vector<vector<int> > placement( int n){
if (n > 7) throw "error";
set <vector <int> > p;
vector <int> temp (n,0);
p.insert (temp);
for (int i = 0; i < 3; i ++) placement(n, p);
vector <vector <int> > s;
s.assign (p.begin(), p.end());
return s;
}
bool tryput(vector <vector <int> > &board, int current, vector<int> & comb){
for (int i = 0; i < comb.size(); i ++){
if ((board[current][i] == 1 || board[current+1][i]) && comb[i] == 1) return false;
}
return true;
}
void put(vector <vector <int> > &board, int current, vector<int> & comb){
for (int i = 0; i < comb.size(); i ++){
if (comb[i] == 1){
board[current][i] = 1;
board[current+1][i] = 1;
}
}
return;
}
void undo(vector <vector <int> > &board, int current, vector<int> & comb){
for (int i = 0; i < comb.size(); i ++){
if (comb[i] == 1){
board[current][i] = 0;
board[current+1][i] = 0;
}
}
return;
}
int place (vector <vector <int> > &board, int current, vector < vector <int> > & all_comb){
int m = board.size();
if (current >= m) throw "error";
if (current == m - 1) return 1;
int count = 0;
for (int i = 0; i < all_comb.size(); i ++){
if (tryput(board, current, all_comb[i])){
put(board, current, all_comb[i]);
count += place(board, current+1, all_comb) % 10000007;
undo(board, current, all_comb[i]);
}
}
return count;
}
int place (int m, int n){
if (m == 0) return 0;
if (m == 1) return 1;
vector < vector <int> > all_comb = placement(n);
vector <vector <int> > board(m, vector<int>(n, 0));
return place (board, 0, all_comb);
}
int main(){
cout << place(3, 4) << endl;
return 0;
}
time complexity O(n^3 * exp(m))
to reduce the space usage try bit vector.
to reduce the time complexity to O(m*(n^3)), try dynamic programming.
to reduce the time complexity to O(log(m) * n^3) try divide and conquer + dynamic programming.
good luck

find the largest sub- matrix full of ones in linear time

Given an n by n matrix with zeros and ones, find the largest sub-
matrix full of ones in linear time. I was told that a solution with
O(n) time complexity exists. If there are n^2 elements in a n X n
matrix how does a linear solution exist?
Unless you have a non-standard definition of submatrix this problem is NP-hard by reduction from maximum clique.
You can't search a n x n matrix in n time. Counterexample: a matrix of zeros with a single element set to one. You have to check every element to find where that one is, so time must be at least O(n^2).
Now if you say that the matrix has N = n^2 entries, and you only consider submatrices that form a contiguous block, then you should be able to find the largest submatrix by walking diagonally across the matrix, keeping track of every rectangle of ones as you go. You could in general have up to O(sqrt(N)) rectangles active simultaneously, and you would need to search in them to figure out which rectangle was the largest, so you ought to be able to do this in O(N^(3/2) * log(N)) time.
If you can pick arbitrary rows and columns to form your submatrix, then I don't see any obvious polynomial time algorithm.
The solution is linear in the number of entries, not in the number of rows or columns.
public static int biggestSubMatrix(int[][] matrix) {
int[][] newMatrix = new int[matrix.length][matrix[0].length];
for (int i = 0; i < matrix.length; i++) {
int sum = 0;
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 1) {
sum++;
newMatrix[i][j] = sum;
} else {
sum = 0;
newMatrix[i][j] = 0;
}
}
}
int maxDimention = 0;
int maxSubMatrix = 0;
for (int i = 0; i < newMatrix[0].length; i++) {
//find dimention for each column
maxDimention = calcHighestDimentionBySmallestItem(newMatrix, i);
if(maxSubMatrix < maxDimention ){
maxSubMatrix = maxDimention ;
}
}
return maxSubMatrix;
}
private static int calcHighestDimentionBySmallestItem(int[][] matrix, int col) {
int totalMaxDimention =0;
for (int j = 0; j < matrix.length; j++) {
int maxDimention = matrix[j][col];
int numItems = 0;
int min = matrix[j][col];
int dimention = 0;
for (int i = j; i < matrix.length; i++) {
int val = matrix[i][col];
if (val != 0) {
if (val < min) {
min = val;
}
numItems++;
dimention = numItems*min;
if(dimention>maxDimention){
maxDimention = dimention;
}
} else { //case val == 0
numItems = 0;
min = 0;
}
}
if(totalMaxDimention < maxDimention){
totalMaxDimention = maxDimention;
}
}
return totalMaxDimention;
}

Resources