poj-3071
来源:互联网 发布:ubuntu配置keras环境 编辑:程序博客网 时间:2024/05/22 13:47
//528K 94MS G++ #include <cstdio>#include <cstring>#include <cmath>const int MAX = 130;double P[MAX][MAX];double DP[MAX][9];int N;int teamNum;void getVSId(int curTeamId, int winTime, int & beginVSId, int & endVsId) { int teamMemberCapcity = pow(2, winTime); beginVSId = 1; endVsId = beginVSId + teamMemberCapcity - 1; while(1) { if (curTeamId >= beginVSId && curTeamId <= endVsId) { break; } else { beginVSId = endVsId + 1; endVsId = beginVSId + teamMemberCapcity - 1; } } int middleId = (beginVSId + endVsId)>>1; if (curTeamId <= middleId) { beginVSId = middleId+1; } else { endVsId = middleId; } // printf("getVSId %d %d %d %d\n", curTeamId, winTime, beginVSId, endVsId);}void beginDP() { for (int winTime = 1; winTime <= N; winTime++) { for (int teamId = 1; teamId <= teamNum; teamId++) { if (winTime == 1) { if (teamId%2) { // is odd, VS teamId +1 DP[teamId][1] = P[teamId][teamId+1]; } else { // is even, VS teamId -1 DP[teamId][1] = P[teamId][teamId-1]; } // printf("DP %d %d %lf\n", teamId, 1, DP[teamId][1]); } else { int beginVSId; int endVsId; getVSId(teamId, winTime, beginVSId, endVsId); double tmp = 0.0; for (int i = beginVSId; i <= endVsId; i++) { tmp += DP[i][winTime-1]*P[teamId][i]; // // printf("%lf %lf %lf %lf\n", // // DP[i][winTime-1], P[teamId][i], // DP[i][winTime-1]*P[teamId][i], tmp); } DP[teamId][winTime] = tmp*DP[teamId][winTime-1]; // printf("DP %d %d %lf %d %d\n", teamId, winTime, DP[teamId][winTime], beginVSId, endVsId); } } }}void getMostPossibleWinner() { beginDP(); int winnerId = 0; double maxP = 0.0; for (int i = 1; i<= teamNum; i++) { if (maxP < DP[i][N]) { maxP = DP[i][N]; winnerId = i; } } // printf("%d %lf\n", winnerId, maxP); printf("%d\n", winnerId);}int main() { while(scanf("%d", &N) != EOF) { if (N == -1) { return 0; } teamNum = pow(2, N); memset(P, 0, sizeof(P)); memset(DP, 0, sizeof(DP)); for (int i = 1; i <= teamNum; ++i) { for (int j = 1; j <= teamNum; ++j) { double Pij; scanf("%lf", &Pij); P[i][j] = Pij; } } getMostPossibleWinner(); }}
披着概率外衣的DP基础题,在写getVsID时犯了个低级错误.
题目咋一看比较唬人,不过结合着例子分析一下,DP的关系就出来了:
首先,题目指明了,比赛的对手安排:
1对2, 3对4 ...... N-1对N.
那么,对于1来说,赢一场的概率就是 P(1,2)(1击败2的概率)
而对于第二轮比赛,按照题目的规定,
1的选手只能是 3或者4,那么赢得概率就是 P(1,2)( P(1,3)*P(3,4) + P(1,4)*P(4,3) )
就这样递推,会发现,
某个选手i, 赢得N场比赛的概率DP[i][N]可以这样表示:
DP[i][N-1] (DP[A1][N-1]P(i,A1) + DP[A2][N-1]P(i,A3) + ... + DP[AN][N-1]P(i,AN))(A1... AN是 i在第N场比赛中可能遭遇的对手),
那么如何确定A1....AN, 可以观察发现:
对于1来说,第一场比赛的对手只可能是2,
第二场比赛的对手只可能是 3, 4
第三场比赛的对手只可能是 5 6 7 8
.......
可以发现,对于某个选手i来说,在第N轮比赛中,他是从一个规模为2的N-1次方的团体中脱颖而出的,而与之相对的也是一个2的N-1次方大小的团队,
这个团队的所有对手都可能会成为i 在第N轮比赛的对手。(对于该团队某个人 j, 能和i比赛的概率就是在此团队胜出的概率,就是DP[j][N-1])
getVsId就是求出与i在第N轮比赛中可能比赛的对手的序号范围,步骤也很简单,
对于第N论比赛,
i 脱颖而出的团队 和 可能做i对手的团队 会一起组成一个 连续 的 2的N次方大小的团队,
先确定这个团队T的范围,然后确定i是在T的前半部分(那么对手就在后半部分),还是后半部分(那么对手就在前半部分)。
最后利用上面的DP递推方程求出即可.
- POJ 3071
- poj 3071
- poj 3071
- POJ 3071
- poj-3071
- poj 3071
- poj 3071 Football
- poj 3071 football
- 【概率dp】POJ 3071
- poj 3071 概论 dp
- POJ 3071 Football
- POJ-3071-Football
- poj 3071 概率dp
- poj 3071 Football
- poj 3071 Football
- POJ 3071 Football
- POJ 3071 Football
- POJ 3071 Football
- C++类型转换方式总结
- 最小化到托盘并有图标闪烁效果
- Object-C 声明属性为什么用下划线,代码规范和编程风格
- 归并排序 java实现
- (转)在团队中进行单元测试/TDD的12条经验
- poj-3071
- C语言基础
- loadrunner 发送中文参数
- 修改Eclipse格式化代默认长度
- 1.Attach(E-UTRAN Initial)
- TCP/IP常见协议及实现
- 数据库分库分表
- MySQL与Oracle 差异比较之五存储过程&Function
- android json解析及简单例子