HDU4800 二维dp 状态转移很灵活

【题意】:N种队伍,每两个队伍I,J之间PK, I 赢的概率是PK[I][J]

M轮PK,双方开始各选一只队伍,若你打败了对手,你可以选择在下一次更换成他手上的队伍,假设你每次都选择最容易最终获胜的方法,求连续打赢M场概率的最大的概率。

【分析】:

dp[i][j]:表示用j号队员打败了第i个对手的最大的概率。

昨天晚上一直W。

dp很容易写错,下面是我的经验

1、尽量要考虑第一层的边界(多是多个入口的题目要这样)

2、下标一定要对

3、dp定义数组一定不能过小,不然会越界出错

4、初始化注意下标范围

出错时检查:

1、输入输出1、下标定义2、初始化的下标3、小数据4、状态方程的逻辑性是否正确

我觉得这道题的巧妙在于,分析复杂度后你会发现是N*M的,但却有着三维的外衣

for(int i=2;i<=N;i++){
     for(int j=0;j<M;j++){
      if (j==pk[i-1]){
         for(int k=0;k<M;k++){
           dp[i][j]=fmax(dp[i][j],dp[i-1][k]*p[j][pk[i]]);
         }
        }else {
           dp[i][j]=dp[i-1][j]*p[j][pk[i]];
      }
   }
}

那么最终ans=max(dp[N][i])枚举i即可

【代码】:

 1 #include<iostream>
 2 #include<stdio.h>
 3 
 4 using namespace std;
 5 
 6 double dp[10005][125];
 7 double p[125][125];
 8 int pk[10005];
 9 
10 int N,M;
11 
12 double fmax(double a,double b){
13     if(a-b>0) return a;else return b;
14 }
15 int main(){
16     //freopen("out.txt","w",stdout);
17     while(~scanf("%d",&M)){
18         M=(M)*(M-1)*(M-2)/6;
19         for(int i=0;i<M;i++){
20             for(int j=0;j<M;j++) scanf("%lf",&p[i][j]);
21         }
22         scanf("%d",&N);
23         for(int i=1;i<=N;i++) scanf("%d",&pk[i]);
24 
25         for(int i=0;i<M;i++) dp[1][i]=p[i][pk[1]];
26         for(int i=0;i<M;i++){
27             for(int j=2;j<=N;j++) dp[j][i]=0.0;
28         }
29         for(int i=2;i<=N;i++){
30             for(int j=0;j<M;j++){
31                 if (j==pk[i-1]){
32                     for(int k=0;k<M;k++){
33                         dp[i][j]=fmax(dp[i][j],dp[i-1][k]*p[j][pk[i]]);
34                     }
35                 }else {
36                     dp[i][j]=dp[i-1][j]*p[j][pk[i]];
37                 }
38             }
39         }
40 
41         double ans=-1.0;
42         for(int i=0;i<M;i++) ans=fmax(ans,dp[N][i]);
43 
44         printf("%lf
",ans);
45 
46     }
47     return 0;
48 }
View Code
原文地址:https://www.cnblogs.com/little-w/p/3768614.html