1. 程式人生 > >狀態壓縮+概率dp

狀態壓縮+概率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();
    }

}