[BZOJ1706][usaco2007 Nov]relays 奶牛接力跑
1706: [usaco2007 Nov]relays 奶牛接力跑
Time Limit: 5 Sec Memory Limit: 64 MB Submit: 708 Solved: 368 [Submit][Status][Discuss]Description
FJ的N(2 <= N <= 1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目。至于进行接力跑的地点 自然是在牧场中现有的T(2 <= T <= 100)条跑道上。 农场上的跑道有一些交汇点,每条跑道都连结了两个不同的交汇点 I1_i和I2_i(1 <= I1_i <= 1,000; 1 <= I2_i <= 1,000)。每个交汇点都是至少两条跑道的端点。 奶牛们知道每条跑道的长度length_i(1 <= length_i <= 1,000),以及每条跑道连结的交汇点的编号 并且,没有哪两个交汇点由两条不同的跑道直接相连。你可以认为这些交汇点和跑道构成了一张图。 为了完成一场接力跑,所有N头奶牛在跑步开始之前都要站在某个交汇点上(有些交汇点上可能站着不只1头奶牛)。当然,她们的站位要保证她们能够将接力棒顺次传递,并且最后持棒的奶牛要停在预设的终点。 你的任务是,写一个程序,计算在接力跑的起点(S)和终点(E)确定的情况下,奶牛们跑步路径可能的最小总长度。显然,这条路径必须恰好经过N条跑道。
Input
* 第1行: 4个用空格隔开的整数:N,T,S,以及E
* 第2..T+1行: 第i+1为3个以空格隔开的整数:length_i,I1_i,以及I2_i, 描述了第i条跑道。
Output
* 第1行: 输出1个正整数,表示起点为S、终点为E,并且恰好经过N条跑道的路 径的最小长度
Sample Input
2 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
Sample Output
10
题意为图上从$S$到$E$走$N$条路径,路径上的最小边权为多少
可以发现,把矩阵乘法的$\sum$改成取$min$一样满足分配律
求把图的邻接矩阵的$N$次方即可
但是矩阵规模太大要TLE,可以发现只有很少的边,只有边两端的点有用,离散化一下即可
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; char buf[10000000], *ptr = buf - 1; inline int readint(){ int f = 1, n = 0; char ch = *++ptr; while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = *++ptr; } while(ch <= '9' && ch >= '0'){ n = (n << 1) + (n << 3) + ch - '0'; ch = *++ptr; } return f * n; } const int maxn = 1000 + 10; struct Matrix{ int n, m, num[110][110]; Matrix(){} Matrix(int _n, int _m){ n = _n; m = _m; memset(num, 0x3f, sizeof(num)); } Matrix operator * (const Matrix &a){ Matrix b(n, a.m); for(int i = 1; i <= n; i++) for(int j = 1; j <= b.m; j++) for(int k = 1; k <= m; k++) b.num[i][j] = min(b.num[i][j], num[i][k] + a.num[k][j]); return b; } }; Matrix ksm(Matrix a, int b){ Matrix s = a; b--; while(b){ if(b & 1) s = s * a; b >>= 1; a = a * a; } return s; } int N, T, S, E; int w[maxn], u[maxn], v[maxn]; int num[maxn * 2], cnt = 0; int main(){ fread(buf, sizeof(char), sizeof(buf), stdin); N = readint(); T = readint(); S = readint(); E = readint(); num[++cnt] = S; num[++cnt] = E; for(int i = 1; i <= T; i++){ w[i] = readint(); num[++cnt] = u[i] = readint(); num[++cnt] = v[i] = readint(); } sort(num + 1, num + cnt + 1); cnt = unique(num + 1, num + cnt + 1) - (num + 1); S = lower_bound(num + 1, num + cnt + 1, S) - num; E = lower_bound(num + 1, num + cnt + 1, E) - num; for(int i = 1; i <= T; i++){ u[i] = lower_bound(num + 1, num + cnt + 1, u[i]) - num; v[i] = lower_bound(num + 1, num + cnt + 1, v[i]) - num; } Matrix ans(cnt, cnt); for(int i = 1; i <= T; i++) ans.num[u[i]][v[i]] = ans.num[v[i]][u[i]] = w[i]; ans = ksm(ans, N); printf("%d\n", ans.num[S][E]); return 0; }