疯子的算法总结(九) 图论中的矩阵应用 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,放里面就是标准的矩阵乘法,因为这个只用一次,所有对于枚举的状态是等价的。

 1     for(int k=1; k<=cnt; k++)
 2     {
 3         for(int i=1; i<=cnt; i++)
 4         {
 5             for(int j=1; j<=cnt; j++)
 6             {
 7                 c[i][j]=Min(a[i][k]+b[k][j],c[i][j]);
 8             }
 9         }
10     }

每做一次类矩阵乘法,就代表将M,N松弛后多一条经过边,那么经过T次松弛后就会得到N,M经过T条边的最短距离,既然是类矩阵乘法,是不是遵循结合律呢?答案是的。对于矩阵,前面是经过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\n",solve(p[S],p[E],n,cnt));
    return 0;
}

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

原文地址:https://www.cnblogs.com/lunatic-talent/p/11366418.html

时间: 2024-11-10 13:55:53

疯子的算法总结(九) 图论中的矩阵应用 Part 1+POJ3613 Cow Relays的相关文章

算法7-6:图论中的难题

二部图 难度:★★ 二分图是图论中的一种特殊模型,指顶点可以分成两个不相交的集使得在同一个集内的顶点不相邻(没有共同边)的图. 下图是一个二分图的例子,红点之间不会相邻,白点之间不会相邻. 判断图中是否存在环 难度:★★ 通过深搜就可以解决了. 欧拉环 难度:★★ 从一个顶点出发,所有的边都只经过一次,最后回到起点.判断一张图中是否存在这样的路径. 哈密尔顿环 难度:★★★★ 从一个顶点出发,所有的顶点都经过一次,最后回到起点.判断一张图中是否存在这样的路径. 这个是一个经典的NP完全问题,目前

【算法】关于图论中的最小生成树(Minimum Spanning Tree)详解

喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 本节纲要 什么是图(network) 什么是最小生成树 (minimum spanning tree) 最小生成树的算法 什么是图(network)? 这里的图当然不是我们日常说的图片或者地图.通常情况下,我们把图看成是一种由"顶点"和"边"组成的抽象网络.在各个"顶点"间可以由"边"连接起来,使两个顶点间相互关联起来.图的结构可以描述多种复杂的数据对象,

算法7-2:图论接口

本节介绍如何在程序中表示一张图. 顶点 在程序中,顶点用整数表示就可以了.因为整数可以作为数组的下标,也可以作为哈希表的键.所以用整数是最方便的. 当然,在一张图中可能会出现一些异常情况,比如自己连接自己,两个顶点之间存在多个边.这些异常情况也是要考虑的. 接口 为了表示一张图,就要创建专门的对象来保存图.这个对象起名叫做Graph好了.它的接口是下面这样的. public class Graph { // 创建一个带有V个顶点的图 Graph(int V); // 从输入流创建一张图,输入流的

算法7-1:图论简介

无向图 无向图由顶点和边组成,边用于连接两个顶点.下面这张地图就是无向图的一个例子. OPTE工程 OPTE工程的目标就是绘制整个互联网的样子.下图是2010年的互联网.互联网也是无向图的一个例子.这张图是用LGL软件进行绘制的.有兴趣的同学可以研究一下:http://www.opte.org/ 术语 在图论中,有些术语是必须要知道的,不然没办法学习. 顶点:图中最基本的元素 边:连接两个顶点的线就是边 路径:由一个顶点到另一个顶点所经过的边 环:从一个顶点出发,经过一些边,最后到达原先的顶点,

【算法总结】图论-并查集

[算法总结]图论-并查集 一.概念:并查集 并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中.这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受:即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1-3秒)内计算出试题需要的结果,只能用并查集来

【算法总结】图论-最短路径

[算法总结]图论-最短路径 一.概念 最短路径问题.即寻找图中某两个特定结点间最短的路径长度.所谓图上的路径,即从图中一个起始结点到一个终止结点途中经过的所有结点序列,路径的长度即所经过的边权和. 二.Floyd算法 用邻接矩阵保存原图,那么此时邻接矩阵中 edge[i][j]的值即表示从结点 i 到 结点j,中间不经过任何结点时距离的最小值(若它们之间有多条边,取最小权值保存至邻接矩阵:也可能为无穷,即不可达).假设结点编号为 1 到 N,我们再考虑从结点i 到结点j中间只能经过编号小于等于1

非阻塞算法在并发容器中的实现【转】

转自:https://www.ibm.com/developerworks/cn/java/j-lo-concurrent/ 非阻塞算法在 Java 中的应用越来越广泛 , ConcurrentLinkedQueue 是 java. concurrent 包中基于非阻塞算法实现的并发容器的典范.通过本文,您将了解非阻塞算法的工作原理及其在 ConcurrentLinkedQueue 中的具体实现机制. 简介 非阻塞算法在更细粒度的层面协调争用,它比传统的锁有更高的并发性.随着非阻塞算法在 Jav

x264代码剖析(十五):核心算法之宏块编码中的变换编码

x264代码剖析(十五):核心算法之宏块编码中的变换编码 为了进一步节省图像的传输码率,需要对图像进行压缩,通常采用变换编码及量化来消除图像中的相关性以减少图像编码的动态范围.本文主要介绍变换编码的相关内容,并给出x264中变换编码的代码分析. 1.变换编码 变换编码将图像时域信号变换成频域信号,在频域中图像信号能量大部分集中在低频区域,相对时域信号,码率有较大的下降. H.264对图像或预测残差采用4×4整数离散余弦变换技术,避免了以往标准中使用的通用8×8离散余弦变换逆变换经常出现的失配问题

C++11新特性应用--介绍几个新增的便利算法(不更改容器中元素顺序的算法)

总所周知,C++ STL中有个头文件,名为algorithm,即算法的意思. The header<algorithm>defines a collection of functions especially designed to be used on ranges of elements. 所以,要八一八这个头文件中C++11新增的几个算法,今天主要描述的几个算法不改变容器中元素的顺序. 这里还要啰嗦一句,使用stl算法时,如果与lambda表达式组合使用,那么代码会更加简洁. find_