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;
    }
    
  • 相关阅读:
    HDU 2089 不要62
    HDU 5038 Grade(分级)
    FZU 2105 Digits Count(位数计算)
    FZU 2218 Simple String Problem(简单字符串问题)
    FZU 2221 RunningMan(跑男)
    FZU 2216 The Longest Straight(最长直道)
    FZU 2212 Super Mobile Charger(超级充电宝)
    FZU 2219 StarCraft(星际争霸)
    FZU 2213 Common Tangents(公切线)
    FZU 2215 Simple Polynomial Problem(简单多项式问题)
  • 原文地址:https://www.cnblogs.com/Rye-Catcher/p/9152413.html
Copyright © 2011-2022 走看看