zoukankan      html  css  js  c++  java
  • Luogu P2886 Cow Relays

    题目大意

      求在一张有(m)条边无向连通图中,点(s)到点(t)的经过(k)条边的最短路((1 leq m leq 100)(1 leq k leq 10^6))。

    题解

      边数(m)很小,显然点数(n)也很小,不超过(200),我们可以先离散化处理。
      我们可以得到(n)个点之间的邻接矩阵,其中矩阵中的(a[i][j])就相当于(i)到点(j)的经过(1)条边的最短路
      此时我们设(dp[i][j][k'])表示点(i)到点(j)的经过(k')条边的最短路,显然有

    [dp[i][j][1] = a[i][j] ]

      且

    [dp[i][j][k'] = min { dp[i][l][k' - 1]+ dp[l][j][k' - 1] }, k' > 1 ]

      显然,朴素的dp复杂度为(O(kn^2))
      观察这个过程,其实很像矩阵乘法,同样的,我们也可以用矩阵快速幂来优化,这样复杂度就降到$O(n^2 log{k}) $了。

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    
    #define MAX_M (100 + 5)
    
    using namespace std;
    
    int K, m, s, t;
    int u[MAX_M], v[MAX_M];
    long long w[MAX_M];
    int tmp[MAX_M << 1];
    int to[1000005], n;
    
    struct Matrix
    {
    	long long mat[MAX_M][MAX_M];
    	
    	Matrix()
    	{
    		memset(mat, 0x3f, sizeof mat);
    		return;
    	}
    	
    	friend Matrix operator * (Matrix a, Matrix b)
    	{
    		Matrix c;
    		for(int i = 1; i <= n; ++i)
    		{
    			for(int j = 1; j <= n; ++j)
    			{
    				for(int k = 1; k <= n; ++k)
    				{
    					c.mat[i][j] = min(c.mat[i][j], a.mat[i][k] + b.mat[k][j]);
    				}
    			}
    		}
    		return c;
    	}
    	
    	friend Matrix operator *= (Matrix & a, Matrix b)
    	{
    		return a = a * b;
    	}
    };
    
    Matrix a;
    
    int main()
    {
    	cin >> K >> m >> s >> t;
    	for(int i = 1; i <= m; ++i)
    	{
    		cin >> w[i] >> u[i] >> v[i];
    		tmp[i << 1 ^ 1] = u[i];
    		tmp[i << 1] = v[i];
    	}
    	sort(tmp + 1, tmp + m + m + 1);
    	for(int i = 1; i <= (m << 1); ++i)
    	{
    		if(tmp[i] != tmp[i - 1]) to[tmp[i]] = ++n;
    	}
    	for(int i = 1; i <= m; ++i)
    	{
    		u[i] = to[u[i]];
    		v[i] = to[v[i]];
    		a.mat[u[i]][v[i]] = min(a.mat[u[i]][v[i]], w[i]);
    		a.mat[v[i]][u[i]] = min(a.mat[v[i]][u[i]], w[i]);
    	}
    	--K;
    	Matrix res = a;
    	while(K)
    	{
    		if(K & 1) res *= a;
    		a *= a;
    		K >>= 1;
    	}
    	cout << res.mat[to[s]][to[t]];
    	return 0;
    }
    
  • 相关阅读:
    算法面试题
    学习进度条(一)
    代码作业——四则运算
    构建之法阅读笔记01
    本学期的阅读计划与快速阅读《构建之法》后提出问题
    自我介绍及学期目标
    对天天开心消消乐(订餐系统)的建议
    《构建之法》阅读笔记01-快速阅读后的几个问题。
    二柱子之随机四则运算
    自我介绍
  • 原文地址:https://www.cnblogs.com/kcn999/p/11355046.html
Copyright © 2011-2022 走看看