## Question:

Found one interesting problem. I will think about a solution and it would be nice to hear your suggestions:

Every month, James Bond receives a list of missions. Based on his rich experience, he calculates the probability of successfully completing the missions of each of his Jimi Bond number X cousins.

Your program must process this data and find the division of missions between cousins to give you the highest probability that all missions will be completed successfully.

Note: The probability that all missions will be successful is equal to the product of the probabilities that individual missions will be successful.

Input format

The first line contains an integer N – the number of missions (1 <= N <= 20). The next N lines contain N integers each from 0 to 100, inclusive. The j-th integer on the i-th line is the probability that cousin i will successfully complete mission j. The probability is given as a percentage.

Output Format

Print the maximum probability of successful completion of all missions, in percent.

A conclusion that differs from the official answer by no more than +0.000001 will be accepted.

Examples

`input input input 2 2 3 100 100 0 50 25 60 100 50 50 50 0 13 0 50 12 70 90 output output output 50.000000 25.00000 9.10000`

Explanation for the 3rd example:

If Jimmy 1 assigns the 3rd mission, Jimmy 2 assigns the 1st mission, and Jimmy 3 assigns the 2nd mission, then we get a success rate of 1.0 * 0.13 * 0.7 = 0.091 = 9.1%. All other mission distribution options give a lower probability of success.

** PS** A question for the administration: I often solve problems of this type (sports programming) and if I offer them for solving (also often) on this forum, will you think that I flooded your site, and will it follow this ban?

## Answer:

Like I figured it out. I'll test it tonight and report the results.

Solution:

DP on bit masks. We will store in the array

fthe answers of a smaller dimension to our problem. Indicesf– distribution of missions for cousins.Consider

f[i]. Let's look at the binary representation of the numberi. For example i = 100110.

```
|**№ бита** | 5 | 4 | 3 | 2 | 1 | 0 |
|------------+---+---+---+---+---+---|
|**знач. i** | 1 | 0 | 0 | 1 | 1 | 0 |
```

This means that

f[i]contains the answer, and if a task was given to a cousin with numberk, then thek-th bit is equal to 1. Moreover, if the number of non-zero bits in numberiis 3, then we distributed cousins for the first 3 missions.

More specific implementation:

Iterate over all the masks (from 0 to 2^20 – 1 ~ 10^6) representing our distribution (1). For each mask, we count the number of units in it – this is the number of distributed missions

m(2). We look: which cousins do not perform any tasks with us (3). We try to assign a taskv+1to some cousin. (4) all

**a[i, j]** – probability of completion of mission **j** by cousin **i**

```
for msk := 0 to pow[n] - 1 do begin //pow[w] = 2^w; (1)
v := q(msk); //(2)
for i := 1 to n do // перебираем всех кузин
if msk and pow[i-1] = 0 then //(3)
f[msk or pow[i-1]] := max(f[msk or pow[i-1]],f[msk]*a[v+1,i]);// (4)
end;
```

we get the answer when all the cousins are distributed, i.e. all bits = 1 (f[2^n-1]).

So the solution runs in N*2^N ~ 20.000.000 (< 1 second the algorithm will run).

Full code:

```
const
maxN = 21;
maxS = 1 shl maxN;
var
n,m,i,j,msk,v : longint;
a : array [1..maxN,1..maxN] of double;
f : array [1..maxS] of double;
pow : array [0..maxN] of longint;
function q(w : longint) : longint;
var
res : longint;
begin
res := 0;
while w > 0 do begin
if w and 1 = 1 then
inc(res);
w := w shr 1;
end;
q := res;
end;
function max(w1,w2 : double) : double;
begin
if w1 > w2 then
max := w1
else
max := w2;
end;
begin
readln(n);
for i := 1 to n do
for j := 1 to n do begin
read(a[i,j]);
a[i,j] := a[i,j] / 100;
end;
pow[0] := 1;
for i := 1 to maxN do
pow[i] := pow[i-1] shl 1;
for i := 1 to n do
f[pow[i-1]] := a[1,i];
for msk := 0 to pow[n] - 1 do begin
v := q(msk);
for i := 1 to n do
if msk and pow[i-1] = 0 then
f[msk or pow[i-1]] := max(f[msk or pow[i-1]],f[msk]*a[v+1,i]);
end;
writeln(f[pow[n]-1]*100:0:10);
end.
```