HDU6331 Problem M. Walking Plan

题意:

给出一张有\(N\)个点的有向图,有\(q\)次询问,每次询问从\(s\)到\(t\)且最少走\(k\)条边的最短路径是多少

\(N\le 50, q\le 10^5, k\le 10^4\)

题解:

如果暴力预处理的话复杂度是\(kN^3\)也就是\(1.25\times 10^9\),空间上肯定开不起

第二个想法就是对邻接矩阵进行矩阵快速幂,对于每次询问都要跑一次,复杂度是\(qN^3\log k\)复杂度更高了

考虑分摊复杂度,\(k\)最多是\(10^4\),那么可以每\(\lfloor\sqrt{k}\rfloor\)的长度跑一次最短路,跑\(\lceil\frac{k}{\lfloor\sqrt{k}\rfloor}\rceil\)次,最后计算的时候询问\(k\)可以把\(k\)拆成\(l\times \sqrt{k} + r\),然后用两个对应的最短路矩阵再找一次最短路即可,要注意的是,最短路不一定是单调的,也就是说可能走更多的边可以得到更短的路径,但是多走的边不会超过\(N\),因为两点之间的最短路长度是不会超过顶点数的,所以预处理时需要计算的是\(u\)到\(v\)走了至少\(k\)步的最短路,最后的复杂度是\(\sqrt{k}N^3+qN\)大概是\(2\times 10^7\)

view code
//#pragma GCC optimize("O3")
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<bits/stdc++.h>
using namespace std;
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
const int MAXN = 55;
const int INF = 0x3f3f3f3f;
int n, m;
struct Matrix{
int A[MAXN][MAXN];
Matrix(){ for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) A[i][j] = INF; }
void clear(){ for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) A[i][j] = INF; }
Matrix operator * (const Matrix &rhs) const{
Matrix ret;
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
ret.A[i][j] = min(ret.A[i][j],A[i][k] + rhs.A[k][j]);
return ret;
}
};
Matrix dis1[155], dis100[111];
void solve(){
scanf("%d %d",&n,&m);
dis1[1].clear();
for(int i = 1; i <= m; i++){
int u, v, w;
scanf("%d %d %d",&u,&v,&w);
dis1[1].A[u][v] = min(dis1[1].A[u][v],w);
}
for(int i = 2; i <= 150; i++) dis1[i] = dis1[i-1] * dis1[1];
dis100[1] = dis1[100];
for(int i = 2; i <= 100; i++) dis100[i] = dis100[i-1] * dis100[1];
for(int i = 149; i >= 1; i--)
for(int u = 1; u <= n; u++)
for(int v = 1; v <= n; v++)
dis1[i].A[u][v] = min(dis1[i].A[u][v],dis1[i+1].A[u][v]);
int q;
scanf("%d",&q);
while(q--){
int s, t ,k;
scanf("%d %d %d",&s,&t,&k);
int ret = INF;
if(k<=100) ret = dis1[k].A[s][t];
else{
int l = (k-1) / 100, r = k - l * 100;
for(int i = 1; i <= n; i++) ret = min(ret,dis100[l].A[s][i] + dis1[r].A[i][t]);
}
printf("%d\n",ret==INF?-1:ret);
}
}
int main(){
int tt;
for(scanf("%d",&tt); tt; tt--) solve();
return 0;
}

最新文章

  1. 原生Android App项目调用Untiy导出的Android项目
  2. String类实现
  3. Spring将多个配置文件引入一个配置文件中
  4. 爆料喽!!!开源日志库Logger的使用秘籍
  5. flex box 布局
  6. iOS使用sqlite3原生语法进行增删改查以及FMDB的使用
  7. 一些Xcode 5的使用提示和技巧
  8. kafka服务安装-SuSE Linux Enterprise Server 11 SP3
  9. Win7 Cygwin环境试验Nutch tutorial遇到的异常解决方法
  10. 关于IE,Chrome,Firefox浏览器的字符串拼接问题
  11. tyvj/joyoi 1305 最大子序和
  12. c#反射(2)
  13. 禅道项目管理系统整合Selenium IDE的思路
  14. SVN常用命令说明
  15. learning makefile = and :=
  16. C++中的return和exit区别
  17. security相关链接整理
  18. Python 反射机制
  19. [hadoop读书笔记] 第十章 管理Hadoop集群
  20. elasticsearch安装与使用(2)-- centos7 安装测试的集群工具elasticsearch head

热门文章

  1. 肌肤管家SkinRun V3S智能皮肤检测仪,用AI探索肌肤问题
  2. mmall商城用户模块开发总结
  3. MySQL使用SQL操作数据表的增加、修改和删除
  4. [Usaco2002 Feb]Rebuilding Roads重建道路
  5. VBA调用数独求解器
  6. E2.在shell中正确退出当前表达式
  7. 简话http请求
  8. Uber三代API 生命周期管理平台实现 Uber
  9. GraphQL两年实战
  10. (Sqlserver)sql求连续问题