/*
小Z 的襪子
Description
ZYB 很喜歡襪子,他決定送一些襪子給機房裏的人。機房裏有n 個人,但是他們腳的尺碼可能不一樣,
一共有m 種尺碼,第i 個人的尺碼爲j 的概率爲aij(ai1+...+aim=1)。
ZYB會帶來n雙襪子,並逐個詢問機房裏的人,如果他的尺碼的襪子還有,ZYB就會送給他一雙,否則將他跳過。
ZYB想知道他帶n 雙襪子來最多期望送出幾雙。
讀入格式
第一行讀入兩個數n和m,接下來n行每行讀入m 個整數表示aij*1000。
輸出格式
輸出一個數表示答案。
Sol:
先不考慮一個人要帶多少種什麼樣的襪子
考慮不同種的襪子。
如果給定n個人,帶某種襪子,他期望送出的襪子是和別的種類的襪子無關
而又由於期望的線性性質,E(X) = p1*E(x1)+p2*E(x2)+....+pn*E(xn)
我們只要dp出n個人,第k種襪子,帶j雙期望能送出多少雙。
dp[i][j][k]表示前i個人,帶j雙尺碼爲k的襪子,期望能送出多少雙
g[i][j], n個人,帶i雙尺碼爲j的襪子,期望能送出多少雙
那麼g[i][j]=dp[n][i][j]
現在考慮不同種的襪子裝包
f[i][j], 前i種襪子,共帶j雙襪子,期望能送出多少雙
f[i][j] = max(f[i-1][k]+g[j-k][i])
就可以O(n^3)解決了
*/
using namespace std;
int n, m;
double p[maxn][maxn/10];
double dp[110][110][110], g[110][110], f[110][110];
int main(){
//freopen("gift.in", "r", stdin);freopen("gift.out", "w", stdout);
scanf("%d%d", &n, &m);
int x;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
scanf("%d", &x);
p[i][j] = x / 1000.0;
}
}
//前i個人,帶j雙尺碼爲k的襪子,期望能送出多少雙
for(int k = 1; k <= m; k ++)
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= i; j ++)
dp[i][j][k] = (dp[i-1][j-1][k] + 1) * p[i][k] + dp[i-1][j][k] * (1 - p[i][k]);
//g[i][j], n個人,帶i雙尺碼爲j的襪子,期望能送出多少雙
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
g[i][j] = dp[n][i][j];
//f[i][j],前i種襪子,共帶j雙襪子,期望能送出多少雙
//f[i][j] = max(f[i-1][k]+g[j-k][i])
for(int i = 1; i <= m; i ++)
for(int j = 0; j <= n; j ++)
for(int k = 0; k <= j; k ++)
f[i][j] = max(f[i][j], f[i-1][k] + g[j-k][i]);
printf("%.12f\n", f[m][n]);
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 3010
using namespace std;
int n, m;
struct Pair{
int x; double y;
Pair(int x = 0, double y = 0):x(x), y(y){}
bool operator<(const Pair& k)const{
if(y != k.y)return y < k.y;
return x < k.x;
}
};
priority_queue<Pair> Q;
int tot, dl1[maxn * 3], dl2[maxn * 3], fr[maxn * 3];
double p[maxn][maxn/10], a[maxn * 3][maxn], b[maxn * 3];
double ans;
inline void cal(){
int x = dl1[tot];
for(int i = 1; i <= n; i ++)
a[tot][i] = a[tot][i-1]*(1-p[i][x])+a[fr[tot]][i-1]*p[i][x];
b[tot] = b[fr[tot]] + a[tot][n];
}
int main(){
freopen("gift.in", "r", stdin); freopen("gift.out", "w", stdout);
scanf("%d%d", &n, &m);
int x;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
scanf("%d", &x);
p[i][j] = x / 1000.0;
}
}
for(int i = 1; i <= m; i ++){
dl1[i] = i, dl2[i] = 1, a[i][0] = 1;
tot ++; cal();
Q.push(Pair(i, 1 - b[i]));
}
for(int i = 1; i <= n; i ++){
Pair P = Q.top(); Q.pop();
ans += P.y; tot ++; fr[tot] = P.x;
dl1[tot] = dl1[P.x], dl2[tot] = dl2[P.x] + 1;
cal(), P.x = tot, P.y = 1 - b[tot], Q.push(P);
}
printf("%.12lf\n", ans);
return 0;
}