题目描述

给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种。
将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点。

输入

第一行包含三个整数n,m,k(1<=n<=40,1<=m<=1000,1<=k<=10^18)。
接下来m行,每行三个整数u,v,c(1<=u,v<=n,u不等于v,1<=c<=3),表示从u出发有一条到v的单向边,边长为c。
可能有重边。

输出

包含一行一个正整数,即第k短的路径的长度,如果不存在,输出-1。

样例输入

6 6 11
1 2 1
2 3 2
3 4 2
4 5 1
5 3 1
4 6 3

样例输出

4


题解

矩阵乘法

如果边长只为1的话,很容易想到使用矩阵乘法解决。把邻接矩阵的$2^i$记录,直到路径条数足够为止。此时需要统计的是路径长度小于等于某数的路径数,因此新建一个计数器,每个点向它连边,然后计数器连一个自环即可。然后按照倍增LCA的方法按$i$从大到小处理即可。

那如果边长为2或3呢?可以考虑拆点解决(不能拆边因为边数过多,无法矩乘)。对于每个点再建两个辅助节点并连边,分别代表长度为2、3,长度为2时从第一个辅助节点连出去,长度为3时从第二个辅助节点连出去,即可得到答案。

这里嘴上说着真容易= =

事实上,本题会爆long long特别多。因为边数是点数的指数级别的。所以判路径是否超过k时很复杂,正解的话需要在矩乘里面写,外面判断时也要写,非常的复杂。

好在本题数据弱,因此不需要在矩乘里面写,直接在外部判断即可。

时间复杂度$O(n^3\log k)$。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll m;
int n;
struct data
{
ll v[121][121];
ll* operator[](int a) {return v[a];}
data operator*(data &a)const
{
int i , j , k;
data ans;
for(i = 0 ; i <= 3 * n ; i ++ )
for(j = 0 ; j <= 3 * n ; j ++ )
ans[i][j] = 0;
for(i = 0 ; i <= 3 * n ; i ++ )
for(j = 0 ; j <= 3 * n ; j ++ )
for(k = 0 ; k <= 3 * n ; k ++ )
ans[i][j] += v[i][k] * a[k][j];
return ans;
}
bool check()
{
ll ret = 0;
int i;
for(i = 1 ; i <= n ; i ++ )
if((ret += v[i][0] - 1) >= m)
return 1;
return 0;
}
}A[70] , Now , Tmp;
bool judge(data &x , data &y , data &z)
{
data tmp = x * y;
if(tmp[0][0] == -1) return 0;
int i;
ll ret = 0;
for(i = 1 ; i <= n ; i ++ )
if((ret += tmp[i][0]) >= m)
return 0;
z = tmp;
return 1;
}
int main()
{
int q , i , x , y , z;
ll ans = 0;
scanf("%d%d%lld" , &n , &q , &m);
A[0][0][0] = 1;
for(i = 1 ; i <= n ; i ++ ) Now[i][i] = A[0][i][0] = A[0][i][i + n] = A[0][i + n][i + 2 * n] = 1;
for(i = 1 ; i <= q ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , A[0][x + (z - 1) * n][y] ++ ;
for(i = 1 ; ; i ++ )
{
if(i > 65)
{
puts("-1");
return 0;
}
A[i] = A[i - 1] * A[i - 1];
if(A[i].check()) break;
}
for(i -- ; ~i ; i -- )
{
Tmp = Now * A[i];
if(!Tmp.check()) Now = Tmp , ans += (1ll << i);
}
printf("%lld\n" , ans);
return 0;
}

【bzoj4386】[POI2015]Wycieczki 矩阵乘法的更多相关文章

  1. BZOJ4386[POI2015]Wycieczki——矩阵乘法+倍增

    题目描述 给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种.将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点. 输入 第 ...

  2. BZOJ4386 [POI2015]Wycieczki 矩阵+倍增

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4386 题解 一眼就可以看出来是邻接矩阵快速幂. 可是这里的边权不为 \(1\).不过可以发现, ...

  3. BZOJ 4386 Luogu P3597 [POI2015]Wycieczki (矩阵乘法)

    题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=4386 (luogu) https://www.luogu.org/pro ...

  4. BZOJ4386 : [POI2015]Wycieczki

    将每个点拆成三个点,并将转移转化为矩阵乘法,然后倍增即可求出第$k$短路的长度,注意对爆long long情况的处理. 时间复杂度$O(n^3\log k)$. #include<cstdio& ...

  5. BZOJ4386[POI2015]Wycieczki / Luogu3597[POI2015]WYC - 矩乘

    Solution 想到边权为$1$的情况直接矩乘就可以得出长度$<=t$ 的路径条数, 然后二分check一下即可 但是拓展到边权为$2$,$3$ 时, 需要新建节点 $i+n$ 和 $i+2n ...

  6. 【BZOJ-4386】Wycieczki DP + 矩阵乘法

    4386: [POI2015]Wycieczki Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 197  Solved: 49[Submit][Sta ...

  7. bzoj 4386: [POI2015]Wycieczki

    bzoj 4386: [POI2015]Wycieczki 这题什么素质,爆long long就算了,连int128都爆……最后还是用long double卡过的……而且可能是我本身自带大常数吧,T了 ...

  8. *HDU2254 矩阵乘法

    奥运 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submissi ...

  9. *HDU 1757 矩阵乘法

    A Simple Math Problem Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

随机推荐

  1. RHEL7 本地yum源配置

    配置yum 源 1.挂载DVD光盘到/mnt   因为配置时候路径名里面不能有空格,否则不能识别  [root@ mnt]# mount /dev/cdrom /mnt 2.在目录/etc/yum.r ...

  2. appium---adb通过wifi连接手机

    前几天接到领导的安排,想要测试下apk的耗电量,可以通过手机adb命令进行监控手机电量的变化:但是这样如果通过USB连接手机的话,USB就会自动给手机进行充电,无法达到我们想要的结果,于是想到了通过w ...

  3. Bootstrap 历练实例 - 按钮(Button)插件复选框

    复选框(Checkbox) 您可以创建复选框按钮 组,并通过向 btn-group 添加 data 属性 data-toggle="buttons" 来添加复选框按钮组的切换. & ...

  4. 51nod——1086、1257背包问题V2(多重背包二进制拆分转01) V3(分数规划+二分贪心)

    V3其实和dp关系不大,思想挂标题上了,丑陋的代码不想放了.

  5. SAP事件 Event Flow(转载)

    1 报表过程事件 报表过程事件是在报表运行过程中由系统自动控制,按照一定次序被触发的事件,其目的是从数据库中选择数据并整理,准备进行列表输出.这些事件从报表程序启动开始就被系统顺序触发,现分述如下: ...

  6. 爬虫学习(五)——使用handler管理器对象进行数据爬取的步骤

    # 使用管理器对象进行爬取数据的步骤 import urllib.requesturl = "https://www.baidu.com/"# 创建handler的管理器对象han ...

  7. 认识mysql(2)

    1.表字段的操作 1.语法 :alter table 表名 执行动作; 2.添加字段(add) alter table 表名 add 字段名 数据类型; alter table 表名 add 字段名 ...

  8. Node.js 特点

      1.单线程 在Java.PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程.而每个线程需要耗费大约2MB内存.也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数 ...

  9. myeclipse10.5 crack(2012-12-27-bd 写的日志迁移

    首先去网上下一个破解文件如图: 解压过后打开的文件夹如图: 再打开crack文件夹如图: 运行run.bat如果点击它没反应就是你没有安装jdk,它如果运行就如图所示: 到这一步就在第一个方框user ...

  10. java中的继承 (2013-10-11-163 写的日志迁移

    继承:为了解决代码重用 定义: 子类通过继承父类,可以调用父类中非私有的属性和方法,达到重用的目的,通过关键字extends实现:   ################以下为代码演示: class A ...