poj 3613 经过k条边最短路 floyd+矩阵快速幂

http://poj.org/problem?id=3613

s->t上经过k条边的最短路

先把1000范围的点离散化到200中,然后使用最短路可以使用floyd,由于求的是经过k条路的最短路,跑k-1次“floyd”即可(使用矩阵快速幂的思想)。

把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <iostream>
#include <sstream>
#include <algorithm>
using namespace std;
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr0(x) memset(x,0,sizeof(x))
#define clr1(x) memset(x,-1,sizeof(x))
#define eps 1e-9
const double pi = acos(-1.0);
typedef long long LL;
const int inf = 0x7fffffff;
const int maxn = 205;
map <int , int> mp;
int k,m,st,en;
int n;//floyd矩阵大小
struct Matrix{
    int mat[maxn][maxn];
    void init(){
        for(int i = 0;i < maxn;++i)
            for(int j = 0;j < maxn;++j)
                mat[i][j] = inf;
    }
};
Matrix ans,tmp,_tmp;
void copy(Matrix &b,Matrix a){
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= n;++j)
            b.mat[i][j] = a.mat[i][j];
}
void floyd(Matrix &a,Matrix b,Matrix c){
    a.init();
    for(int k = 1;k <= n;++k)
    for(int i = 1;i <= n;++i)
    for(int j = 1;j <= n;++j){
        if(b.mat[i][k] == inf || c.mat[k][j] == inf)
            continue;
        if(a.mat[i][j] > b.mat[i][k]+c.mat[k][j])
            a.mat[i][j] = b.mat[i][k]+c.mat[k][j];
    }
}
int has[1005];
void init()
{
    n = 0;
    clr0(has);
    ans.init(),tmp.init();
    for(int i = 0;i < maxn;++i)
        ans.mat[i][i] = 0;
    int u,v,w;
    for(int i = 0;i < m;++i){
        RD3(w,u,v);
        if(has[u] == 0)
            has[u] = ++n;
        if(has[v] == 0)
            has[v] = ++n;
        if(tmp.mat[has[u]][has[v]] > w)
            tmp.mat[has[v]][has[u]] = tmp.mat[has[u]][has[v]] = w;
    }
}
void work()
{
    while(k){
        if(k&1){
            copy(_tmp,ans);
            floyd(ans,_tmp,tmp);
        }
        copy(_tmp,tmp);
        floyd(tmp,_tmp,_tmp);
        k>>=1;
    }
    printf("%d\n",ans.mat[has[st]][has[en]]);
}
int main()
{
    while(~RD2(k,m)){
        RD2(st,en);
        init();
        work();
    }
    return 0;
}
时间: 2024-08-12 21:54:04

poj 3613 经过k条边最短路 floyd+矩阵快速幂的相关文章

POJ 3613 Cow Relays (floyd + 矩阵快速幂)

题目大意: 求刚好经过K条路的最短路 我们知道如果一个矩阵A[i][j] 表示表示 i-j 是否可达 那么 A*A=B  B[i][j]  就表示   i-j 刚好走过两条路的方法数 那么同理 我们把i-j 的路径长度存到A 中. 在A*A的过程中,不断取小的,那么最后得到的也就是i - j 走过两条路的最短路了. 当然也是利用到了floyd的思想. 然后要求出K次的最短路,那么就是矩阵快速幂的工作了. 注意要离散化.用map #include <cstdio> #include <io

POJ 3613 Cow Relays (Floyd + 矩阵快速幂 + 离散化 神题!)

Cow Relays Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5611   Accepted: 2209 Description For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout

POJ 3070 Fibonacci【斐波那契数列/矩阵快速幂】

Fibonacci Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 17171   Accepted: 11999 Description In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequen

java写最短路和矩阵快速幂

Til the Cows Come Home POJ - 2387 Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the morning milking. Bessie needs her beauty sleep, so she wants to get back as quickly a

(POJ 3744)Scout YYF I(概率dp+矩阵快速幂)

概率dp入门题,转移方程为dp[i]=dp[i-1]*p+dp[i-2]*(1-p) 因为n个数字上限很大,所以常规的概率dp基本不可能,要用矩阵优化. 把路程分成n+1段,分别计算通过每段的成功率,即刚好跨越地雷的概率(dp[地雷x+1]) 算好每段之后把每段的成功率相乘. (若有两颗地雷相邻那么成功率是0) #include<iostream> #include<cstdio> #include<vector> #include<set> #includ

poj 3150 Cellular Automaton(矩阵快速幂)

http://poj.org/problem?id=3150 大致题意:给出n个数,问经过K次变换每个位置上的数变为多少.第i位置上的数经过一次变换定义为所有满足 min( abs(i-j),n-abs(i-j) )<=d的j位置上的数字之和对m求余. 思路: 我们先将上述定义表示为矩阵 B =  1 1 0 0 1 1 1 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 1 1 B[i][j] = 表示i与j满足上述关系,B[i][j] = 0表示i与j不满足上述关系.根据这个

POJ POJ 2778 DNA Sequence AC自动机 + 矩阵快速幂

首先建立Trie和失败指针,然后你会发现对于每个节点 i 匹配AGCT时只有以下几种情况: i 节点有关于当前字符的儿子节点 j 且安全,则i 到 j找到一条长度为 1的路. i 节点有关于当前字符的儿子节点 j 且 不安全,则i 到 j没有路. i 节点没有关于当前字符的儿子节点 但是能通过失败指针找到一个安全的节点j,那么 i 到 j 找到一条长度为1的路. 关于节点安全的定义: 当前节点不是末节点且当前节点由失败指针指回跟节点的路径上不存在不安全节点,那么这个节点就是安全节点. 然后问题就

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分)

POJ 3233 - Matrix Power Series ( 矩阵快速幂 + 二分) #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long LL; #define MAX_SIZE 30 #define CLR( a, b ) memset( a, b, sizeof(a) ) int MOD = 0; int n, k; st

【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】

还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key