https://www.nowcoder.com/acm/contest/57/C
题目:小C现在要参加一场wannafly挑战赛,一场挑战赛一共有n道题,一共有m分钟。对于第i道题,小C解决它需要恰好j分钟的概率是pi,j。小C每次会选择某一道没做完的题,然后把它解决(不能中途放弃),之后再决策下一道要做的题是哪道。求小C在最优策略下,期望能做出几道题。
思路:状态压缩+概率dp,E(期望)=∑XiPi。则:dp[i][j]表示状态i下,j分钟能做出期望题数,假设pre是i的前一个状态,那么有:dp[i][j]=∑(dp[pre][j-k]+1)p[i^pre][k]。
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.math.BigDecimal;
public class Main {
static StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static int nextInt() throws IOException {
in.nextToken();
return (int)in.nval;
}
static double nextDouble() throws IOException {
in.nextToken();
return (double)in.nval;
}
static String next() throws IOException {
in.nextToken();
return (String)in.sval;
}
static double a[][] = new double[7][183];
static double dp[][] = new double[1 << 6][183];
public static void main(String[] arg) throws IOException {
int n, m;
n = nextInt();
m = nextInt();
double tmp;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
a[i][j] = nextDouble();
}
}
for(int i = 1; i < (1 << n); i++) { // 不同方案
for(int j = 1; j <= m; j++) { // 枚举花费时间、
for(int k = 1; k <= n; k++) { // 当前这种方案都是使用了那道题目,
if((i & (1 << (k - 1))) > 0) { // 用了题目 k
tmp = 0;
for(int zz = 1; zz <= j; zz++) { // 用zz分钟做k题目
tmp += (1 + dp[i ^ (1 << (k - 1))][j - zz]) * a[k][zz]; // i ^ (1 << (k - 1))即未选择k时的方案、这里dp[i][j]计算的是期望
}
dp[i][j] = Math.max(dp[i][j], tmp);
}
}
}
}
BigDecimal bd = new BigDecimal(dp[(1 << n) - 1][m]).setScale(5, BigDecimal.ROUND_HALF_DOWN);
out.println(bd);
out.flush();
}
}