状态压缩+概率dp

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();
    }

}

猜你喜欢

转载自blog.csdn.net/qq_36706625/article/details/80196988
今日推荐