首页 > 其他分享 >P2886题解

P2886题解

时间:2023-07-10 18:46:49浏览次数:52  
标签:count temp int 题解 矩阵 ++ P2886 mp

题目大意

给定起点 \(S\) 和终点 \(T\),求从起点到终点恰好经过 \(N\) (\(N\) 给定)条边的最短路径。

solution

发现本题点数巨多,但是边数小到可怜,我们可以只保留一部分点,先判断连通性,不连通直接输出即可。

当 \(S\) 和 \(T\) 连通时,我们设 \(G^k\) 为经过 \(k\) 条边后最短路的邻接矩阵。我们发现下面一个事实:

当我们定义矩阵乘法为关于 \(\{min, +\}\) 的运算时,\(G^m \times G^n = G^{n+m}\)。

因此这题就是对邻接矩阵进行一个广义矩阵乘法。

同时我们发现 \(k\) 的范围完全支持我们进行快速幂,因此我们可以用矩阵快速幂,每次矩阵乘法复杂度为 \(|E|^3\),总复杂度为 \(|E|^3\log k\)。

  • 完整代码(远古时期做的了,马蜂不太一样)
#include <bits/stdc++.h>
using namespace std;
const int N = 210;
int k, m, s, e, n;
int g[N][N];
int res[N][N];
unordered_map<int, int> mp;

void mul(int c[][N], int a[][N], int b[][N])
{
    int temp[N][N];
    memset(temp, 0x3f, sizeof temp);
    for(int k = 1; k <= n; k ++ )
        for(int i = 1; i <= n; i ++ )
            for(int j = 1; j <= n; j ++ )
                temp[i][j] = min(temp[i][j], a[i][k] + b[k][j]);
                
    memcpy(c, temp, sizeof temp);
}

void qmi()
{
    memset(res, 0x3f, sizeof res);
    for(int i = 1; i <= n; i ++ ) res[i][i] = 0;
    
    while(k)
    {
        if(k & 1) mul(res, res, g);
        mul(g, g, g);
        k >>= 1;
    }
}

int main()
{
    cin >> k >> m >> s >> e;
    
    if(!mp.count(s)) mp[s] = ++ n;
    if(!mp.count(e)) mp[e] = ++ n;
    
    memset(g, 0x3f, sizeof g);
    while (m -- )
    {
        int a, b, c;
        cin >> c >> a >> b;
        if(!mp.count(a)) mp[a] = ++ n;
        if(!mp.count(b)) mp[b] = ++ n;
        a = mp[a], b = mp[b];
        g[a][b] = g[b][a] = min(g[a][b], c);
    }
    
    qmi();
    
    cout << res[mp[s]][mp[e]] << endl;
    
    return 0;
}

标签:count,temp,int,题解,矩阵,++,P2886,mp
From: https://www.cnblogs.com/crimsonawa/p/17541996.html

相关文章

  • Largest-Smallest-Cyclic-Shift题解
    题目链接本题码量不大,但是事实上是一道极其难想的思维题。题目描述你有\(a\)个a,\(b\)个b,\(c\)个c。要求用这\(a+b+c\)个字母拼接成一个字符串,使得这个字符串的最小表示法在所有能拼成的字符串中最大。补充:最小表示法,将一个字符串的最后一个字符放到首位,重复这个操作,......
  • AT-abc214-g题解
    题目描述给定两个排列\(p,q\),要求统计满足\(\foralli,r_i\not=p_i,r_i\not=q_i\)的排列\(r\)的数量。对\(1000000007\)取模数据范围\(n\le3000\)。solution本题要求统计数量,反正我想了半天没想到怎么正向统计(bushi),因此我们考虑容斥。设\(h_i\)为只看其中......
  • P3599题解
    本题是一道比较典的构造题,拿来扩宽扩宽大家的眼界吧。Task1试判断能否构造并构造一个长度为\(n\)的\(1\simn\)的排列,满足其\(n\)个前缀和在模\(n\)的意义下互不相同。很容易想到的一点是:\(n\)一定排在第一位,因为如果排在别的位,加上\(n\)后在模\(n\)意义下是不......
  • CF1421E题解
    题目链接本题作为一道本人思考了50分钟没想出来的大思维题,我觉得可以用来扩宽一下大家的视野。本题中,我们每次都会选取两个相邻的数\(a_i\)和\(a_{i+1}\),同时将这两位变为一位,这一位上填的数为\(-(a_i+a_{i+1})\)。很容易想到的一个\(O(n^3)\)的dp做法是区间dp,设\(f[......
  • NOIP2013-2023题解
    本文章主要是为了不想卷题的时候不是特别颓废而准备本文章是为了总结NOIP最近的题目(为了今年NOIP做准备),目前还没写完,尽量做的全面一些。2013积木大赛给定一个长度为\(n\)的序列\(h_i\),初始有一个全为\(0\)的序列,每次操作可以任意选择\(L,R\),使得\([L,R]\)这段区......
  • CF1545D-题解
    题目链接题目描述有\(n\)个人和\(k\)个间隔相同时间的时刻,每个人都向正方向做匀速直线运动。给出每个时刻(\(0\simk-1\))的所有人的坐标集合(无序),在这\(nk\)个数中有一个数是错误的,找出这个错误的数并将其改正。数据范围:\(5\len\le1000\),\(7\lek\le1000\)。加......
  • 【问题解决】docker login报错 org.freedesktop.Secret.Error.IsLocked: Cannot creat
    问题场景环境docker24.0.2社区版UbuntuServer18.04LTS刚刚执行dockerlogin登录仓库报错:hellxz@bigdata:~/dockerTest$dockerloginharbor.xxx.com.cnUsername:hellxzPassword:**Message:17:26:21.611:Remoteerrorfromsecretservice:org.freedesktop.Se......
  • CF1827D 题解
    problem&blog。很好的题。用到一些关于重心的trick。不妨认为只有一个重心\(\text{maxx}\)。设当前节点数为\(n\),重儿子所在的子树的大小为\(\text{maxsiz}\),那么答案即\(n-2\times\text{maxsiz}\),方法是往重儿子的那个子树爆加节点。因此需要在线维护\(\text{maxx}......
  • CF1601F Two Sorts 题解--zhengjun
    link这里提供一种不用meetinmiddle的方法,速度比较可观。发现性质开始简单的推一下式子。\(\sum(i-a_i)\bmodp=\sum(rk_i-i-p\times\lfloor\frac{rk_i-i}{p}\rfloor)=-p\times\sum\lfloor\frac{rk_i-i}{p}\rfloor,p=998244353\)于是,只需求出\(\sum\lfloor\frac{rk_i-......
  • C++题解——格子游戏
    题目链接:一本通TFLSOJ思路:使用并查集给点连接,如果在连接过程中遇到已连接的点二次连接,就输出代码:#include<bits/stdc++.h>usingnamespacestd;structnode{ intx,y;};nodef[205][205];intn,m;nodefind(nodek){ if(f[k.x][k.y].x==k.x&&f[k.x][k.y].y==k.y)retur......