Consider the below problems statement. There are 100 different types of caps each having a unique id from 1 to 100. Also, there are ‘n’ persons each having a collection of a variable number of caps. One day all of these persons decide to go in a party wearing a cap but to look unique they decided that none of them will wear the same type of cap. So, count the total number of arrangements or ways such that none of them is wearing the same type of cap. Constraints: 1 <= n <= 10 Example:
The first line contains the value of n, next n lines contain collections
of all the n persons.
Input:
3
5 100 1 // Collection of the first person.
2 // Collection of the second person.
5 100 // Collection of the third person.
Output:
4
Explanation: All valid possible ways are (5, 2, 100), (100, 2, 5),
(1, 2, 5) and (1, 2, 100)
Since, number of ways could be large, so output modulo 1000000007
We strongly recommend you to minimize your browser and try this yourself first.
A Simple Solution is to try all possible combinations. Start by picking the first element from the first set, marking it as visited and recur for remaining sets. It is basically a Backtracking based solution.
A better solution is to use Bitmasking and DP.
Let us first introduce Bitmasking.
What is Bitmasking?
Suppose we have a collection of elements which are numbered from 1 to N. If we want to represent a subset of this set then it can be encoded by a sequence of N bits (we usually call this sequence a “mask”). In our chosen subset the i-th element belongs to it if and only if the i-th bit of the mask is set i.e., it equals to 1. For example, the mask 10000101 means that the subset of the set [1… 8] consists of elements 1, 3 and 8. We know that for a set of N elements there are total 2N subsets thus 2N masks are possible, one representing each subset. Each mask is, in fact, an integer number written in binary notation.
Our main methodology is to assign a value to each mask (and, therefore, to each subset) and thus calculate the values for new masks using values of the already computed masks. Usually our main target is to calculate value/solution for the complete set i.e., for mask 11111111. Normally, to find the value for a subset X we remove an element in every possible way and use values for obtained subsets X’1, X’2… ,X’k to compute the value/solution for X. This means that the values for X’i must have been computed already, so we need to establish an ordering in which masks will be considered. It’s easy to see that the natural ordering will do: go over masks in increasing order of corresponding numbers. Also, We sometimes, start with the empty subset X and we add elements in every possible way and use the values of obtained subsets X’1, X’2… ,X’k to compute the value/solution for X. We mostly use the following notations/operations on masks: bit(i, mask) – the i-th bit of mask count(mask) – the number of non-zero bits in the mask first(mask) – the number of the lowest non-zero bit in the mask set(i, mask) – set the ith bit in the mask check(i, mask) – check the ith bit in the mask
How is this problem solved using Bitmasking + DP? The idea is to use the fact that there are upto 10 persons. So we can use an integer variable as a bitmask to store which person is wearing a cap and which is not.
Let i be the current cap number (caps from 1 to i-1 are already
processed). Let integer variable mask indicates that the persons w
earing and not wearing caps. If i'th bit is set in mask, then
i'th person is wearing a cap, else not.
// consider the case when ith cap is not included
// in the arrangement
countWays(mask, i) = countWays(mask, i+1) +
// when ith cap is included in the arrangement
// so, assign this cap to all possible persons
// one by one and recur for remaining persons.
∑ countWays(mask | (1 << j), i+1)
for every person j that can wear cap i
Note that the expression "mask | (1 << j)" sets j'th bit in mask.
And a person can wear cap i if it is there in the person's cap list
provided as input.
If we draw the complete recursion tree, we can observe that many subproblems are solved again and again. So we use Dynamic Programming. A table dp[][] is used such that in every entry dp[i][j], i is mask and j is cap number. Since we want to access all persons that can wear a given cap, we use an array of vectors, capList[101]. A value capList[i] indicates the list of persons that can wear cap i.
Below is the implementation of above idea.
C++
#include<bits/stdc++.h>
#define MOD 1000000007
using namespace std;
vector< int > capList[101];
int dp[1025][101];
int allmask;
long long int countWaysUtil( int mask, int i)
{
if (mask == allmask) return 1;
if (i > 100) return 0;
if (dp[mask][i] != -1) return dp[mask][i];
long long int ways = countWaysUtil(mask, i+1);
int size = capList[i].size();
for ( int j = 0; j < size; j++)
{
if (mask & (1 << capList[i][j])) continue ;
else ways += countWaysUtil(mask | (1 << capList[i][j]), i+1);
ways %= MOD;
}
return dp[mask][i] = ways;
}
void countWays( int n)
{
string temp, str;
int x;
getline(cin, str);
for ( int i=0; i<n; i++)
{
getline(cin, str);
stringstream ss(str);
while (ss >> temp)
{
stringstream s;
s << temp;
s >> x;
capList[x].push_back(i);
}
}
allmask = (1 << n) - 1;
memset (dp, -1, sizeof dp);
cout << countWaysUtil(0, 1) << endl;
}
int main()
{
int n;
cin >> n;
countWays(n);
return 0;
}
|
Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Vector;
class Test
{
static final int MOD = 1000000007 ;
static BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
static Vector<Integer> capList[] = new Vector[ 101 ];
static int dp[][] = new int [ 1025 ][ 101 ];
static int allmask;
static long countWaysUtil( int mask, int i)
{
if (mask == allmask) return 1 ;
if (i > 100 ) return 0 ;
if (dp[mask][i] != - 1 ) return dp[mask][i];
long ways = countWaysUtil(mask, i+ 1 );
int size = capList[i].size();
for ( int j = 0 ; j < size; j++)
{
if ((mask & ( 1 << capList[i].get(j))) != 0 ) continue ;
else ways += countWaysUtil(mask | ( 1 << capList[i].get(j)), i+ 1 );
ways %= MOD;
}
return dp[mask][i] = ( int ) ways;
}
static void countWays( int n) throws Exception
{
String str;
String split[];
int x;
for ( int i= 0 ; i<n; i++)
{
str = br.readLine();
split = str.split( " " );
for ( int j = 0 ; j < split.length; j++) {
x = Integer.parseInt(split[j]);
capList[x].add(i);
}
}
allmask = ( 1 << n) - 1 ;
for ( int [] is : dp) {
for ( int i = 0 ; i < is.length; i++) {
is[i] = - 1 ;
}
}
System.out.println(countWaysUtil( 0 , 1 ));
}
public static void main(String args[]) throws Exception
{
int n;
for ( int i = 0 ; i < capList.length; i++)
capList[i] = new Vector<>();
n = Integer.parseInt(br.readLine());
countWays(n);
}
}
|
Python
from collections import defaultdict
class AssignCap:
def __init__( self ):
self .allmask = 0
self .total_caps = 100
self .caps = defaultdict( list )
def countWaysUtil( self ,dp, mask, cap_no):
if mask = = self .allmask:
return 1
if cap_no > self .total_caps:
return 0
if dp[mask][cap_no]! = - 1 :
return dp[mask][cap_no]
ways = self .countWaysUtil(dp, mask, cap_no + 1 )
if cap_no in self .caps:
for ppl in self .caps[cap_no]:
if mask & ( 1 << ppl) : continue
ways + = self .countWaysUtil(dp, mask | ( 1 << ppl), cap_no + 1 )
ways = ways % ( 10 * * 9 + 7 )
dp[mask][cap_no] = ways
return dp[mask][cap_no]
def countWays( self ,N):
for ppl in range (N):
cap_possessed_by_person = map ( int , raw_input ().strip().split())
for i in cap_possessed_by_person:
self .caps[i].append(ppl)
self .allmask = ( 1 << N) - 1
dp = [[ - 1 for j in range ( self .total_caps + 1 )] for i in range ( 2 * * N)]
print self .countWaysUtil(dp, 0 , 1 ,)
def main():
No_of_people = input ()
AssignCap().countWays(No_of_people)
if __name__ = = '__main__' :
main()
|
C#
using System;
using System.Collections.Generic;
using System.IO;
class Test {
const int MOD = 1000000007;
static StreamReader br
= new StreamReader(Console.OpenStandardInput());
static List< int >[] capList = new List< int >[ 101 ];
static int [, ] dp = new int [1025, 101];
static int allmask;
static long countWaysUtil( int mask, int i)
{
if (mask == allmask)
return 1;
if (i > 100)
return 0;
if (dp[mask, i] != -1)
return dp[mask, i];
long ways = countWaysUtil(mask, i + 1);
int size = capList[i].Count;
for ( int j = 0; j < size; j++) {
if ((mask & (1 << capList[i][j])) != 0)
continue ;
else
ways += countWaysUtil(
mask | (1 << capList[i][j]), i + 1);
ways %= MOD;
}
return dp[mask, i] = ( int )ways;
}
static void countWays( int n)
{
string str;
string [] split;
int x;
for ( int i = 0; i < n; i++) {
str = br.ReadLine();
split = str.Split( ' ' );
for ( int j = 0; j < split.Length; j++) {
x = int .Parse(split[j]);
capList[x].Add(i);
}
}
allmask = (1 << n) - 1;
for ( int i = 0; i < dp.GetLength(0); i++) {
for ( int j = 0; j < dp.GetLength(1); j++) {
dp[i, j] = -1;
}
}
Console.WriteLine(countWaysUtil(0, 1));
}
public static void Main()
{
int n;
for ( int i = 0; i < capList.Length; i++)
capList[i] = new List< int >();
n = int .Parse(br.ReadLine());
countWays(n);
}
}
|
Input:
3
5 100 1
2
5 100
Output:
4
Time Complexity: O(n*2^n), where n is the number of persons. This is because the recursive function is called at most 2^n times and the for loop is executed at most n times.
Auxiliary Space: O(n*2^n), as we are using a dp 2D array of size n*2^n.
This article is contributed by Gaurav Ahirwar. Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above