zoukankan      html  css  js  c++  java
  • 疯子的算法总结(九) 图论中的矩阵应用 Part 1 POJ3613 Cow Relays

    图的存储有邻接矩阵,那么他就具备一些矩阵的性质,设有一个图的demo[100][100];那么demo[M][N]就是M—>N的距离,若经过一次松弛操作demo[M][N]=demo[M][K]+demo[K][N],即为demo[M][N]经过了两条条边的最小距离,floyd是                                   demo[M][N]=Min(demo[M][K]+demo[K][N],demo[M][N]),有可能两点之间直接距离最短,不经过第三边,那我们不考虑不经过两点之间的情况,那么demo[M][N]等于  demo[M][K]+demo[K][N] 枚举K的最小值,于是出现了一类问题,叫做两点之间经过N条边的最短距离,那么类比矩阵乘法,矩阵乘法是求和,我们在这里是求最小值,那么可以改造矩阵乘法得出,不是Floyd,K放在外面和里面没有区别,放外面像是Floyd,放里面就是标准的矩阵乘法,因为这个只用一次,所有对于枚举的状态是等价的。

        for(int k=1; k<=cnt; k++)
        {
            for(int i=1; i<=cnt; i++)
            {
                for(int j=1; j<=cnt; j++)
                {
                    c[i][j]=Min(a[i][k]+b[k][j],c[i][j]);
                }
            }
        }

    每做一次类矩阵乘法,就代表将M,N松弛后多一条经过边,那么经过T次松弛后就会得到N,M经过T条边的最短距离,既然是类矩阵乘法,是不是遵循结合律呢?答案是的。对于矩阵demo^T*demo^W,前面是经过T条边的最小值,后边是经过W条边的最小值,想乘代表经过了T+W条边的最小值,因为每进行一次都是插入一个点,即使点重复,那么他也会有环形出现,但还是经过了T+W条边,如此,我们可以利用矩阵快速幂求解其经过N条边之后的最小值,那么我们会发现矩阵跟图的是密不可分,一定还会有其他的特点去等待发现,它还可以用于求解图的生成树问题,下次更新。

    本思想可以解决POJ3613,好像现在题没了,给一个网站https://www.acwing.com/problem/content/347/,代码附在下方。

    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<set>
    #include<cmath>
    #include<vector>
    #include<map>
    #include<stack>
    #include<bitset>
    #include<cstdio>
    #include<cstring>
    #define Swap(a,b) a^=b^=a^=b
    #define cini(n) scanf("%d",&n)
    #define cinl(n) scanf("%lld",&n)
    #define cinc(n) scanf("%c",&n)
    #define cins(s) scanf("%s",s)
    #define coui(n) printf("%d",n)
    #define couc(n) printf("%c",n)
    #define coul(n) printf("%lld",n)
    #define speed ios_base::sync_with_stdio(0)
    #define Max(a,b) a>b?a:b
    #define Min(a,b) a<b?a:b
    #define mem(n,x) memset(n,x,sizeof(n))
    #define INF  0x3f3f3f3f
    #define maxn  100010
    #define esp  1e-9
    #define mp(a,b) make_pair(a,b)
    using namespace std;
    const int N=300;
    #define clr(a) memset(a,0,sizeof(a))
    int a[N][N],temp[N][N],ans[N][N];
    int used[10*N];
    int p[10*N];
    void floyed(int a[][N],int b[][N],int c[][N],int cnt)
    {
        for(int k=1; k<=cnt; k++)
        {
            for(int i=1; i<=cnt; i++)
            {
                for(int j=1; j<=cnt; j++)
                {
                    c[i][j]=Min(a[i][k]+b[k][j],c[i][j]);
                }
            }
        }
    }
    void copy(int n,int a[][N],int b[][N])
    {
        for(int i=0; i<=n; i++)
            for(int j=0; j<=n; j++)
                a[i][j]=b[i][j],b[i][j]=INF;
    }
    int solve(int s,int t,int n,int cnt)
    {
    
        while(n)
        {
            if(n&1)
            {
                floyed(ans,a,temp,cnt);
                copy(cnt,ans,temp);
            }
            floyed(a,a,temp,cnt);
            copy(cnt,a,temp);
            n>>=1;
        }
        return ans[s][t];
    }
    int main()
    {
        int n,t,S,E;
        scanf("%d%d%d%d",&n,&t,&S,&E);
        int u,v,w;
        int cnt=0;
        mem(ans,0x3f);
        mem(temp,0x3f);
        mem(a,0x3f);
        for(int i=0; i<t; i++)
        {
            scanf("%d%d%d",&w,&u,&v);
            if(!used[u])
            {
                used[u]=1;
                p[u]=++cnt;
                a[cnt][cnt]=temp[cnt][cnt]=ans[cnt][cnt]=0;
            }
            if(!used[v])
            {
                used[v]=1;
                p[v]=++cnt;
                a[cnt][cnt]=temp[cnt][cnt]=ans[cnt][cnt]=0;
            }
            a[p[u]][p[v]]=a[p[v]][p[u]]=w;
        }
        printf("%d
    ",solve(p[S],p[E],n,cnt));
        return 0;
    }
    

    这个题的边不连续,要先离散化。

  • 相关阅读:
    51nod 1412 AVL树的种类(经典dp)
    HDU 6141 I am your Father!(最小树形图+权值编码)
    POJ 3164 Command Network(最小树形图模板题+详解)
    HDU 6125 Free from square(状态压缩+分组背包)
    HDU 6143 Killer Names(容斥原理)
    CSU 1808 地铁(最短路变形)
    HDU 6128 Inverse of sum(同余)
    HDU 6121 Build a tree(完全K叉树)
    HDU 6129 Just do it(杨辉三角)
    HDU 6127 Hard challenge(扫描线)
  • 原文地址:https://www.cnblogs.com/lunatic-talent/p/12798794.html
Copyright © 2011-2022 走看看