Luogu P2886 [USACO07NOV]牛继电器Cow Relays|最短路,倍增

题目链接

题意:给出一张无向连通图,求S到E经过N条边的最短路。

数据范围:边数\(\le 100\),顶点编号\(\le1000\),\(N\le1 \times 10^6\)

题解:

最短路有三种解法,这种数据范围可使用\(floyd\)

可以用\(f[i][j][k]\)表示从\(i\)到\(j\)经过\(k\)条边的最短路,显然TLE

考虑倍增。预处理\(K=2^k\),此时\(f[i][j][k]=min\{f[i][l][k-1] + f[l][j][k-1]\}\)

将\(n\)二进制拆分,显然第\(x\)位为\(1\),就直接调用\(f[][][x]\)。

然后用几乎同样的方法就能求出经过\(k\)条边的最短路了。

需要注意的是,按顶点跑\(floyd\)会超时,所以应该将其离散化。

上代码

#include<bits/stdc++.h>
#define s(S) 1-S%2
#define g(S) S%2
using namespace std;
const int oo=1000000000;
int n,t,s,e,u,v,c,maxp;
int f[1010][1010][20],ans[1010][1010][2],num[1010],snum;
int main()
{
    cin>>n>>t>>s>>e;
    num[s]=1;num[e]=2;snum=2;s=1;e=2;
    for (int i=1;i<=t;i++)
    {
        cin>>c>>u>>v;
        if (num[u]) u=num[u];else num[u]=++snum,u=num[u];
        if (num[v]) v=num[v];else num[v]=++snum,v=num[v];
        f[u][v][0]=f[v][u][0]=c;
        maxp=max(maxp,max(u,v));
    }
    for (int k=0;(1<<k)<=n;k++)
    for (int i=1;i<=maxp;i++)
      for (int j=1;j<=maxp;j++)
      {
        if (k!=0||((!f[i][j][k]))) f[i][j][k]=oo;
      }
     for (int k=1;(1<<k)<=n;k++)
      for (int l=1;l<=maxp;l++)
        for (int i=1;i<=maxp;i++)
          for (int j=1;j<=maxp;j++)
          {
              f[i][j][k]=min(f[i][j][k],f[i][l][k-1]+f[l][j][k-1]);
          }//预处理
    int S=0,sum=1,S1=0;
    while (n&&!(n&1))
    {
        n>>=1;S1++;
    }
    for (int i=1;i<=maxp;i++)
        for (int j=1;j<=maxp;j++)
        {
            ans[i][j][S]=f[i][j][S1];
        }
    n>>=1;S1++;
    while (n&&!(n&1))
    {
        n>>=1;S1++;
    }
    for (int i=1;i<=maxp;i++)
        for (int j=1;j<=maxp;j++)
        {
            ans[i][j][1]=oo;
        }
    while (n)
    {
        S++;S%=2;
        for (int l=1;l<=maxp;l++)
        for (int i=1;i<=maxp;i++)
        for (int j=1;j<=maxp;j++)
        {
            ans[i][j][S]=min(ans[i][j][S],ans[i][l][s(S)]+f[l][j][S1]);
        }
        n>>=1;S1++;
        while (n&&!(n&1))
        {
            n>>=1;S1++;
        }
        for (int i=1;i<=maxp;i++)
        for (int j=1;j<=maxp;j++)
        {
            ans[i][j][s(S)]=oo;
        }
    }//求ans,与上面几乎一致
    cout<<ans[s][e][S]<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/fmj123/p/Luogu2886.html

时间: 2024-11-12 04:22:34

Luogu P2886 [USACO07NOV]牛继电器Cow Relays|最短路,倍增的相关文章

[LUOGU] P2886 [USACO07NOV]牛继电器Cow Relays

https://www.luogu.org/problemnew/show/P2886 给定无向连通图,求经过k条边,s到t的最短路 Floyd形式的矩阵乘法,同样满足结合律,所以可以进行快速幂. 离散化大可不必sort+unique,因为我们甚至并不在乎相对大小,只是要一个唯一编号,可以开一个桶记录 之所以进行k-1次快速幂,是因为邻接矩阵本身就走了一步了. #include<iostream> #include<cstring> #include<cstdio> u

P2886 [USACO07NOV]牛继电器Cow Relays

题目描述 For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout the pasture. Each trail connects two different intersections (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000), each

[USACO07NOV]牛继电器Cow Relays

https://www.luogu.org/problem/P2886 题目描述: 给出一张无向连通图,求$S$到$E$经过$k$条边的最短路. 对于一类$S$到$E$走指定数量的边数,求它的最短路或条数,都可以采用矩阵快速幂的方式解决.我们回忆一下那一个慢得惊人的$floyd$算法,将它的$dp$方程式提取出来. $floyd[i][j]=min(floyd[i][k]+floyd[k][j])$ 如果我们把$floyd$看做一个矩阵,那么矩阵乘法的标准式则为: $floyd[i][j]=\s

[luoguP2886] [USACO07NOV]牛继电器Cow Relays(矩阵)

传送门 矩阵快速幂,本质是floyd 把 * 改成 + 即可 注意初始化 因为只有100条边,所以可以离散化 #include <cstdio> #include <cstring> #include <algorithm> #define N 101 #define min(x, y) ((x) < (y) ? (x) : (y)) int n, t, s, e, cnt; int x[N], y[N], z[N], a[N]; struct Matrix {

Luogu P2419 [USACO08JAN]牛大赛Cow Contest

传递闭包板子,震惊自己之前居然没学过,特此记录一下. #include <bits/stdc++.h> using namespace std; const int N = 110; int n, m, u, v, to[N][N]; int main () { cin >> n >> m; for (int i = 1; i <= m; ++i) { cin >> u >> v; to[u][v] = true; } for (int k

POJ3613 Cow Relays 最短路+矩阵乘法

题意:求恰好经过K条边的最短路 题解:根据Floyd的性质,如果我拿一开始给出的两个边权矩阵(只经过一条边的最短路的邻接矩阵)跑Floyd,得到的一定是只经过两条边的最短路的邻接矩阵(普通的Floyd是用求出的最短路来更新最短路而非用初始矩阵),同理用两条边的邻接矩阵一定能得到四条边的,因此N条边的邻接矩阵一定能由N/2条边的邻接矩阵得到,而当N为奇数时,用N-1的和初始矩阵跑一边就好了.因此套用矩阵乘法和快速幂的思想,就能把复杂度压倒N^2logN. #include <cstdio> #i

【题解】Luogu P2889 [USACO07NOV]挤奶的时间Milking Time

Luogu P2889 [USACO07NOV]挤奶的时间Milking Time 题目描述 传送门Bessie is such a hard-working cow. In fact, she is so focused on maximizing her productivity that she decides to schedule her next N (1 ≤ N ≤ 1,000,000) hours (conveniently labeled 0..N-1) so that she

POJ 3613 Cow Relays 恰好n步的最短路径

http://poj.org/problem?id=3613 题目大意: 有T条路,从s到e走n步,求最短路径. 思路: 看了别人的... 先看一下Floyd的核心思想: edge[i][j]=min(edge[i][j],edge[i][k]+edge[k][j]) i到j的最短路是i到j的直接路径或者经过k点的间接路径,但是矩阵的更新总是受到上一次更新的影响 如果每次的更新都存进新矩阵,那么edge[i][k]+edge[k][j]是不是表示只经过三个点两条边的路径呢? min(edge[i

矩阵十题【十】 poj 3613 Cow Relays

题目链接:http://poj.org/problem?id=3613 题目大意: 输入N,T,S,E,N表示要走的边数,T表示一共有几条边,S表示开始的点,E表示结束的点 给出一张无向连通图,求S到E经过N条边的最短路. N (2 ≤ N ≤ 1,000,000) T (2 ≤ T ≤ 100) (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000) 1 ≤ lengthi  ≤ 1,000 题目主要的思想就是用矩阵的乘法模拟出Floyd进行运算,是个很好的题目. //k步最短路