• csp赛前刷题篇 图论篇 [USACO07NOV]Cow Relays G


    https://www.luogu.com.cn/problem/P2886

    看一眼本题,Floyd算法。那么什么是Floyd算法呢??

      Floyd

    Floyd是一种最短路算法,适用于点数较少的图

    Floyd的本质是动态规划,它的状态定义以及转移:

    f[i][j]f[i][j]为ii到jj的最短距离

    f[i][j]=min(f[i][j],f[i][k]+f[k][j])f[i][j]=min(f[i][j],f[i][k]+f[k][j])

    代码实现:

    	for(int k=1;k<=n;k++)
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++)
    				f[i][j]=min(f[i][j],f[i][k]+f[k][j]);

    下面让我们魔改一下
    令f[k,i,j]表示 从i经过k条边到达j 原Floyd表达 从i 到j走1~k个点,最短路径是多少。
    魔改后 转移方程 f[a+b,i,j]=min(f[a,i,k],f[b,i,k]),k=1~n。
    d[a,i,k] 中的 k不是什么第 k 条边,而是表示从 i 走了 a 条边(就是相当于走了a步)以后到达的结点 k ,因此这个 k 是在 1 ~ N 之间的一个点。
    这个转移方程表示从 i 到 j 走 a+b (x)条边,等于在所有从 i 走 a 条边到 k ,再从 k 走 b (xa) 条边到 j 中取最小值。
    这样我们要求的是经过 N 条边的最短路,最开始输入的每一个都是1条边(经过一条边的两个点的距离),那么我们要得到经过N条边就可以按照上述的方程,加 N-1 次 (d[2,i,j] = d[1,i,k] + d[1,k,j])
    同时,这里可以用快速幂来优化。
    这里有一百条边,用两百个点,给到1000.所以要离散化一下。
    离散化
    即在不i改变数据相对大小的前提下,对数据进行相应的缩小。通常使用STL算法离散化操作。
    步骤为:排序,去重,lower bount。
    代码如下:

       sort(sub_a,sub_a+n);

       int size=unique(sub_a,sub_a+n)-sub_a;//size为离散化后元素个数

       for(i=0;i<n;i++) a[i]=lower_bound(sub_a,sub_a+size,a[i])-sub_a + 1;//k为b[i]经离散化后对应的值

    本题代码如下
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<map>
    
    #define x first
    #define y second
    using namespace std;
    typedef pair<int,int> PII;
    
    const int N =  507;
    
    int k,n,m,S,E;
    int g[N][N];
    int d[N][N];
    
    void mul(int c[][N],int a[][N],int b[][N]){
        static int temp[N][N];
        memset(temp,0x3f,sizeof temp);
        for(int k = 1;k <= n;++k)
            for(int i = 1;i <= n;++i)
                for(int j = 1;j <= n;++j)
                    temp[i][j] = min(temp[i][j],a[i][k] + b[k][j]);
        memcpy(c,temp,sizeof temp);
    }
    
    void qpow(){
        memset(d,0x3f,sizeof d);
        for(int i = 1;i <= n;++i)
            d[i][i] = 0;
        while(k){
            if(k & 1)mul(d, d, g);//d = d * g;
            mul(g, g, g);//g = g * g;
            k >>= 1;
        }
    }
    
    int main(){
        cin>>k>>m>>S>>E;
        memset(g,0x3f,sizeof g);
        //这里g[i][i]不能置为0,因为这里g[i][j]表示的是从i走1条边到达j,i不能经过1条边到i,因此应该也是INF
        map<int,int>ids;
        while(m--){
            int a,b,c;
            scanf("%d%d%d",&c,&a,&b);
            if(!ids.count(a))ids[a] = ++n;
            if(!ids.count(b))ids[b] = ++n;
            a = ids[a],b = ids[b];
    
            g[a][b] = g[b][a] = min(g[a][b],c);
        }
        if(!ids[S])ids[S] = ++n;
        if(!ids[E])ids[E] = ++n;
        S = ids[S],E = ids[E];
    
        qpow();
    
        cout<<d[S][E]<<endl;
        return 0;
    
    }
    View Code
    
    
       
  • 相关阅读:
    node.js代码
    弹性盒和多列布局
    浏览器兼容性
    图片整合与宽高自适应
    百度分享自定义设置
    设置Cookie,登录记住用户登录信息,获取用户登录过得信息
    验证用户是否登录,是否有过注册信息
    循环显示切换
    ajax提交表单 验证
    简单易用的点击展开伸缩效果
  • 原文地址:https://www.cnblogs.com/lbxer/p/13798623.html
Copyright © 2020-2023  润新知