背包dp问题的变体,每一关看成一个背包,用的炸弹数看成重量,通关概率看成物品总价值,然后本关与之前所有关卡用的炸弹数最优分配用分类讨论。注意到若用100个炸弹则必定通关,那么枚举100个或剪枝都行。时间复杂度为o(100nm),最多正好是十的八次方。
1 #include<iostream> 2 #include<vector> 3 #include<cstdio> 4 using namespace std; 5 double dp[1005][1001];//dp[a][b]代表通a关用b个炸弹的最大通过概率 6 7 struct level { 8 int k, b; 9 }; 10 11 double min(double a, double b) 12 { 13 return a < b ? a : b; 14 } 15 16 double max(double a, double b) 17 { 18 return a > b ? a : b; 19 } 20 21 double mayPoint(int k, int b, int x) 22 { 23 return min(1, double(k*x + b) / (double)100); 24 } 25 26 27 int main() 28 { 29 int n, m; 30 scanf("%d%d",&n,&m); 31 vector<level> levels(n+1); 32 for (int i = 1; i <= n; ++i) 33 { 34 int k, b; 35 scanf("%d%d", &k, &b); 36 levels[i].b = b; 37 levels[i].k = k; 38 } 39 for (int i = 0; i <= m; ++i) 40 { 41 dp[0][i] = 1; 42 } 43 for (int i = 1; i <= n; ++i) 44 { 45 for (int nb = 0; nb <= m; ++nb) 46 { 47 for (int b = nb; b <= m; ++b) 48 { 49 dp[i][b] = max(dp[i][b], dp[i - 1][b - nb] * mayPoint(levels[i].k, levels[i].b, nb)); 50 } 51 if (mayPoint(levels[i].k, levels[i].b, nb) >= 1)break; 52 } 53 } 54 for (int i = 0; i <= n; ++i) 55 { 56 for (int j = 0; j <= m; ++j) 57 { 58 cout << dp[i][j] << " "; 59 } 60 cout << endl; 61 } 62 printf("%lf ", dp[n][m]); 63 64 }
(卡了一个小时最后还没做出来,菜swl)