POJ 1946 Cow Cycling

探讨了在CowCycling比赛中如何通过最优策略使至少一名队员以最快速度完成比赛。介绍了比赛的基本规则,包括能量消耗、领导更替及比赛长度等关键参数。

 

Cow Cycling
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 1479 Accepted: 788

&l t;p class="pst">Description

 

The cow bicycling team consists of N (1 <= N <= 20) cyclists. They wish to determine a race strategy which will get one of them across the finish line as fast as possible. 

Like everyone else, cows race bicycles in packs because that's the most efficient way to beat the wind. While travelling at x laps/minute (x is always an integer), the head of the pack expends x*x energy/minute while the rest of pack drafts behind him using only x energy/minute. Switching leaders requires no time though can only happen after an integer number of minutes. Of course, cows can drop out of the race at any time. 

The cows have entered a race D (1 <= D <= 100) laps long. Each cow has the same initial energy, E (1 <= E <= 100). 

What is the fastest possible finishing time? Only one cow has to cross the line. The finish time is an integer. Overshooting the line during some minute is no different than barely reaching it at the beginning of the next minute (though the cow must have the energy left to cycle the entire minute). N, D, and E are integers.

Input

A single line with three integers: N, E, and D 

Output

A single line with the integer that is the fastest possible finishing time for the fastest possible cow. Output 0 if the cows are not strong enough to finish the race. 

Sample Input

3 30 20

Sample Output

7

Hint

[as shown in this chart:

leader E
pack total used this
time leader speed dist minute
1 1 5 5 25
2 1 2 7 4
3 2* 4 11 16
4 2 2 13 4
5 3* 3 16 9
6 3 2 18 4
7 3 2 20 4
* = leader switch

Source

 

 

 

### 解题思路 POJ 3613 Cow Relays 问题要求计算在给定的图中,从起点到终点恰好经过 $k$ 条边的最短路径。常规的暴力解法,即每次走一步更新最短路径,时间复杂度为 $O(k * n^3)$,效率较低。可利用二进制思想和矩阵快速幂的方法,将时间复杂度优化到 $O(logK * n^3)$ [^2]。 具体思路如下: 1. **图的表示**:使用邻接矩阵来表示图,矩阵中的元素 `mat[i][j]` 表示从节点 `i` 到节点 `j` 的最短距离,初始值设为无穷大 `INF`。 2. **矩阵乘法的定义**:普通矩阵乘法是对应元素相乘再相加,而这里定义的矩阵乘法是对应元素相加再取最小值。即 `C.mat[i][j] = min(C.mat[i][j], A.mat[i][k] + B.mat[k][j])`,表示从节点 `i` 经过节点 `k` 到节点 `j` 的最短距离。 3. **矩阵快速幂**:通过不断地将矩阵自乘,利用二进制的思想,快速计算出经过 $k$ 条边的最短路径矩阵。 4. **节点编号映射**:由于节点编号可能不连续,使用一个数组 `f` 来将原始节点编号映射到连续的编号,方便矩阵操作。 ### 代码实现 以下是实现该算法的 C++ 代码: ```cpp #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; #define INF ((1<<30)-1) int n; struct matrix { int mat[201][201]; matrix() { for(int i = 0; i < 201; i++) for(int j = 0; j < 201; j++) mat[i][j] = INF; } }; int f[2001]; matrix mul(matrix A, matrix B) { matrix C; int i, j, k; for(i = 1; i <= n; i++) { for(j = 1; j <= n; j++) { for(k = 1; k <= n; k++) { C.mat[i][j] = min(C.mat[i][j], A.mat[i][k] + B.mat[k][j]); } } } return C; } matrix powmul(matrix A, int k) { matrix B; for(int i = 1; i <= n; i++) B.mat[i][i] = 0; while(k) { if(k & 1) B = mul(B, A); A = mul(A, A); k >>= 1; } return B; } int main() { matrix A; int k, t, s, e, a, b, c; scanf("%d%d%d%d", &k, &t, &s, &e); int num = 1; while(t--) { scanf("%d%d%d", &c, &a, &b); if(f[a] == 0) f[a] = num++; if(f[b] == 0) f[b] = num++; A.mat[f[a]][f[b]] = A.mat[f[b]][f[a]] = c; } n = num - 1; A = powmul(A, k); cout << A.mat[f[s]][f[e]] << endl; return 0; } ``` ### 代码解释 1. **结构体 `matrix`**:定义了一个矩阵结构体,用于存储图的邻接矩阵,构造函数将矩阵元素初始化为无穷大。 2. **函数 `mul`**:实现了自定义的矩阵乘法,计算两个矩阵相乘的结果。 3. **函数 `powmul`**:实现了矩阵快速幂,通过不断地将矩阵自乘,快速计算出经过 $k$ 条边的最短路径矩阵。 4. **主函数 `main`**:读取输入数据,将节点编号映射到连续的编号,初始化邻接矩阵,调用 `powmul` 函数计算经过 $k$ 条边的最短路径矩阵,最后输出从起点到终点的最短距离。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值