POJ 3613Cow Relays( floyd 倍增法)

题意:从s点出发到达e点且n条边的最短路是多少(可以走重复的路径)

图中点<=200,n<=1000,000

思路:folyd可以实现向路径中添边,但是这题与普通的求最短路问题不一样,比如从S到E经过X条边后就已经达到了最短路,这个时候仍然要强制用folyd再添边,尽管添边后就不是最短路了,但是要注意到添加的这边要使最短路损失最小,抓住这点用folyd可以实现强制添边的操作,所以可以从n=1的状态向n的状态转移

所以可以对原来的map进行n-1次folyd,但是n的范围太大,最坏的情况要进行1000000*200^3次运算肯定会T

这时,注意到可以用倍增法加速状态的转移,任何n都可以分解成2^i的和,每个2^i的状态都可以由2^(i-1)的状态直接求得。

也就是当前的map中每个点之间的距离表示经过了2^(i-1)条边,然后对当前的map folyd一次,就可以算出map中每个点之间经过了2^(i-1)+2^(i-1)=2^i 条边的最短路

所以用倍增法加速了状态转移

//628K	94MS
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
#define inf 0x3f3f3f3f
#define M 205
int n,m,st,ed;
int Hash[1005],cnt;
int mapp[M][M],tmp[M][M],n_ans[M][M];

void folyd(int a[M][M],int b[M][M],int c[M][M]){
    for(int k=1;k<=cnt;k++)
    for(int j=1;j<=cnt;j++)
    for(int i=1;i<=cnt;i++)
        if(a[j][i]>b[j][k]+c[k][i])
            a[j][i]=b[j][k]+c[k][i];

}
void map_copy(int a[M][M],int b[M][M]){
    for(int i=1;i<=cnt;i++)
    for(int j=1;j<=cnt;j++){
        a[i][j]=b[i][j];
        b[i][j]=inf;
    }
}
int main(){

    memset(mapp,0x3f,sizeof(mapp));
    memset(tmp,0x3f,sizeof(tmp));
    memset(n_ans,0x3f,sizeof(n_ans));
    for(int i=1;i<=200;i++){
        n_ans[i][i]=0;
        //注意不要让 mapp[i][i]=tmp[i][i]=0,因为要使tmp[i][i]任何时候无穷大因为自身到自身也要通过其他多个牛
        //mapp[i][j]不是inf的值表示必须存在边,不能假定自身到自身是一条权为0的边
        //n_ans[i][i]初始化自身到自身为0是动态规划的边界条件
    }
    scanf("%d%d%d%d",&n,&m,&st,&ed);
    while(m--){
        int val,u,v;
        scanf("%d%d%d",&val,&u,&v);
        if(!Hash[u]){ //对顶点离散化
            Hash[u]=++cnt;
        }
        if(!Hash[v]){
            Hash[v]=++cnt;
        }
        mapp[Hash[u] ][Hash[v] ]=mapp[Hash[v] ][Hash[u] ]=val;
    }
    while(n){
        if(n&1){
            folyd(tmp,n_ans,mapp);
            map_copy(n_ans,tmp);
        }
        folyd(tmp,mapp,mapp);
        map_copy(mapp,tmp);
        n>>=1; //加速状态转移
    }
    printf("%d\n",n_ans[Hash[st] ][Hash[ed] ]);
    return 0;
}
时间: 2024-10-05 23:25:31

POJ 3613Cow Relays( floyd 倍增法)的相关文章

poj 3613Cow Relays

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 the pasture. Each trail connects two different intersections (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000

[POJ 1330] Nearest Common Ancestors (倍增法)

题目同上篇,最近公共祖先. 因为没有清零tot,RE了好多次TAT 一定要初始化啊!! 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<iostream> 5 using namespace std; 6 int root,head[10010]; 7 int next[10010],to[10010],tot; 8 int deep[10010],n; 9 int p[

倍增法

转自http://i.cnblogs.com/EditPosts.aspx?opt=1:很容易懂 1. DFS预处理出所有节点的深度和父节点  void dfs(int u){    int i;    for(i=head[u];i!=-1;i=next[i])      {          if (!deep[to[i]])        {                        deep[to[i]] = deep[u]+1;            p[to[i]][0] = u

LightOJ - 1128 (倍增法 + dp)

唔 已经有一个多月没有写题解了, 其实这一个多月也是做了一些题目的,但是就是比较懒啊,所以都堆在一起没有写了--. 题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26842 题意: 给出一棵树(有默认根), 每个节点有一个权值,再给出q个询问,每个询问包含v k两个变量, 让你输出树根和v节点的路径上,权值大于等于k的离树根最近的节点. 思路: 算是倍增法 + dp的入门练习吧. dp[v][i] 表示节点v

UVa 11149 矩阵的幂(矩阵倍增法模板题)

https://vjudge.net/problem/UVA-11149 题意: 输入一个n×n矩阵A,计算A+A^2+A^3+...A^k的值. 思路: 矩阵倍增法. 处理方法如下,一直化简下去直到变成A. 代码如下: 1 Matrix solve(Matrix base,int x) 2 { 3 if(x==1)return base; 4 Matrix temp=solve(base,x/2); 5 Matrix sum=add(temp,multi(pow(base,x/2),temp)

POJ 2478 Farey Sequence 筛选法求欧拉函数

题目来源:POJ 2478 Farey Sequence 题意:输入n 求 phi(2)+phi(3)+phi(4)+...+phi(n) 思路:用类似筛法的方式计算phi(1), phi(2), ..., phi(n) 再求前缀和 #include <cstdio> #include <cstring> #include <cmath> //欧拉phi函数 const int maxn = 1000010; typedef long long LL; int eule

倍增法+二分 hnu13547 Lily&#39;game

传送门:点击打开链接 题意:给了一个原串A,和一个排列B.每次操作,把串A按照排列B去变换,然后把奇数位的数字全部乘以2.问把原串A经过很多次操作以后,能否得到c*2^d.如果能得到,就输出最小操作次数,否则输出-1 思路:我们来分析一下,首先对于按排列变换的问题,当然第一步是把变换转换成有向图模型,即连一条边i->B[i].我们能发现会得到很多个环. 不同的环答案是独立的.我们对每个环经行考虑.假如A[i]变换以后能变成c*2^d,乘以了x个2,那么就说明从位置i按有向图行走,恰好会经过x个点

poj1330Nearest Common Ancestors以及讲解倍增法求lca

Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20487   Accepted: 10784 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below: In the figure, each node is labeled with an

Codeforces 519E A and B and Lecture Rooms [倍增法LCA]

题意: 给你一棵有n个节点的树,给你m次询问,查询给两个点,问树上有多少个点到这两个点的距离是相等的.树上所有边的边权是1. 思路: 很容易想到通过记录dep和找到lca来找到两个点之间的距离,然后分情况讨论. 一开始困扰我的问题是如果lca不是正中间的点,如何在比较低的复杂度的层面上求解中点. 倍增法lca不光可以在logn的时间复杂度内查询某两个点的lca,还可以实现在logm的时间复杂度能查询某个节点的第m个父亲节点. 算法的核心是用二进制的运算来实现查询. #include<bits/s