zoukankan      html  css  js  c++  java
  • luogu题解 P2886 【牛继电器Cow Relays】-经过K边最短路&矩阵

    • 题目链接:

      https://www.luogu.org/problemnew/show/P2886

    • Update 6.16

      最近看了下《算法导论》,惊奇地发现在在介绍(APSP) ((All Pairs Shortest Path))时的第一个方法就是此法,同时在思考题中看到了不少熟悉的问题,看来《算法导论》还是要多看一下

    • 思路:

      看到这题想了很久,想不到比较优的做法,然后看了书上的解法

      感觉太妙了,将图论与矩阵加速递推结合了起来从而轻而易举地解决了这道题,实在是神奇。

      首先我们构建邻接矩阵(A),最初(A[i][j])表示从i到j直接相连路径长度(即不经过其他的点),若两点不直接相连或(i==j),都设为(inf)

      很明显当(n==0)时最初的(A[i][j])表示经过(n)条边的最短路

      那么(n!=0)时呢?假设(n==1),那么我们只要将初始A矩阵进行如此运算:

      (A[i][j]=min_{1<=k<=n,k!=i,j}(A[i][k]+A[k][j]))

      此时(A[i][j])当然就表示经过(n)条边时从(i)(j)的最短路

      那么当(n==k)时呢?好象我们需(k)次上述运算,但是仔细一看它很想我们的矩阵乘法,显然具有结合律 逃),然后矩阵快速幂就好了...

    • 注意:

      1. inf值最好设大一点,在这里卡了好久

      2. 节点数给出来是1000范围,矩阵乘法会超时,但是边数只有200范围,于是对节点编号离散化。

      3. 不知道为什么POJ上用C++会RE,要用G++

    • 代码:

    /*C++ 11*/
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cstring>
    #include <cctype>
    #include <vector>
    #include <map>
    #define ll long long 
    #define ri register int 
    using namespace std;
    const int maxn=255;
    const int inf=999999999;//inf值要设大 
    int tot=0;
    struct Mat{
    	int g[maxn][maxn];
    	Mat operator ^(const int &k)const{
    		int c=k;
    		//Mat ans=Mat(n);
    		Mat ans=*this;
    		Mat res=ans;
    		while(c){
    			if(c&1)ans=ans*res;
    			res=res*res;
    			c=c>>1;
    		}
    		return ans;
    	}
    	Mat operator *(const Mat &b)const{
    		Mat ans;
    		for(ri i=1;i<=tot;i++){
    			for(ri j=1;j<=tot;j++){
    				ans.g[i][j]=inf;
    			}
    		}
    	   for(ri i=1;i<=tot;i++){
    			   for(ri j=1;j<=tot;j++){
    			   	int tmp=ans.g[i][j];
    			    for(ri k=1;k<=tot;k++){
    				tmp=min(ans.g[i][j],g[i][k]+b.g[k][j]);
    			    }
    			    ans.g[i][j]=tmp;
    		    }
    		}
    		return ans;
    	}
    };
    int N,t,s,e;
    int di[198164],fx[maxn];
    Mat a;
    template <class T>inline void read(T &x){
    	x=0;int ne=0;char c;
    	while(!isdigit(c=getchar()))ne=c=='-';
    	x=c-48;
    	while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
    	x=ne?-x:x;
    	return ;
    }
    int main(){
        int dis,u,v;
    	read(N),read(t),read(s),read(e);
    	for(ri i=1;i<=maxn;i++){
    		for(ri j=1;j<=maxn;j++)
    		a.g[i][j]=inf;
    	}
    	for(ri i=1;i<=t;i++){
    		read(dis),read(u),read(v);
    		if(!di[u])di[u]=++tot,fx[tot]=u;
    		if(!di[v])di[v]=++tot,fx[tot]=v;
    		a.g[di[u]][di[v]]=dis;
    		a.g[di[v]][di[u]]=dis;
    	}
    	a=a^(N-1);
    	printf("%d
    ",a.g[di[s]][di[e]]);
    	return 0;
    }
    
  • 相关阅读:
    C++互斥器:Semaphores
    C++互斥器:Mutex
    内联函数(inline)
    C++显式转换
    线程同步控制
    拷贝构造函数——防篡改
    extern关键字
    虚析构、纯虚析构
    类的友元关系
    char 与 unsigned char的本质区别
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9152413.html
Copyright © 2011-2022 走看看