ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2019-08-02 10:03:17  阅读:211  来源: 互联网

标签:Cow USACO07NOV int Luogu S1 ++ num 1010 短路


题目链接

题意:给出一张无向连通图,求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;
}

标签:Cow,USACO07NOV,int,Luogu,S1,++,num,1010,短路
来源: https://www.cnblogs.com/fmj123/p/Luogu2886.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有