BZOJ4386[POI2015] Wycieczki
来源:互联网 发布:rrb400软件代号 编辑:程序博客网 时间:2024/05/02 04:41
BZOJ4386[POI2015] Wycieczki
Description
给定一张n个点m条边的带权有向图,每条边的边权只可能是1,2,3中的一种。
将所有可能的路径按路径长度排序,请输出第k小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点。
Input
第一行包含三个整数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。
可能有重边。
Output
包含一行一个正整数,即第k短的路径的长度,如果不存在,输出-1。
Sample Input
6 6 11
1 2 1
2 3 2
3 4 2
4 5 1
5 3 1
4 6 3
Sample Output
4
HINT
长度为1的路径有1->2,5->3,4->5。
长度为2的路径有2->3,3->4,4->5->3。
长度为3的路径有4->6,1->2->3,3->4->5,5->3->4。
长度为4的路径有5->3->4->5。
Solution:
这是一道矩阵乘法的题。
首先来看边权是一的情况:
在
要求任意两点之间的路径条数,我们可以添加一个虚拟源点,将它向其他点连边,并给它自己连一条自环(用于矩阵乘法转移)。然后
然后来看这一道题:因为矩阵乘法只能适用于边权为1的情况,而它的边权又只是1或2或3,所以我们把一个点拆成三个点,再进行连边,如图:
然后我们在这个图上做矩阵乘法(倍增Floyd),可以求出长度为
然后就使用倍增的试探方式求出这个答案就可以了。
本题有个神坑:
矩阵乘法(统计答案)的时候有可能爆long long,乘之前应要先判断有没有超过K,否则说明已经超过了K,就标记一下,不更新答案,直接return就可以了。
#include<stdio.h>#include<string.h>#include<iostream>#define ll long long#define M 125 #define Exit {res.m[0][0]=-1;return res;}//标记返回 using namespace std;void Rd(int &res){ char c;res=0; while(c=getchar(),!isdigit(c)); do{ res=(res<<1)+(res<<3)+(c^48); }while(c=getchar(),isdigit(c));}int n,m,tot,id[M][3],cnt[M];ll K;struct Matrix{ ll m[M][M]; Matrix(){ memset(m,0,sizeof(m)); } Matrix operator *(const Matrix &A)const{ Matrix res; for(int i=0;i<=tot;i++) for(int j=0;j<=tot;j++) if(m[i][j]<0||A.m[i][j]<0)Exit; for(int i=0;i<=tot;i++) for(int j=0;j<=tot;j++) if(m[i][j]){ for(int k=0;k<=tot;k++) if(A.m[j][k]){ if(m[i][j]>K/A.m[j][k])Exit; res.m[i][k]+=m[i][j]*A.m[j][k]; if(res.m[i][j]>K)Exit; } } return res; }}a[65],b,c;bool check(){ if(b.m[0][0]<0)return false; ll k=0; for(int i=1;i<=tot;i++){ if(b.m[0][i]&&cnt[i]){ if(b.m[0][i]<0)return false; if(b.m[0][i]>K/cnt[i])return false; k+=b.m[0][i]*cnt[i]; if(k>=K)return false; } } return k<K;}int main(){ Rd(n);Rd(m);cin>>K; for(int i=1;i<=n;i++) for(int j=0;j<3;j++) id[i][j]=++tot; for(int i=1;i<=n;i++){ for(int j=0;j<2;j++) a[0].m[id[i][j]][id[i][j+1]]++; a[0].m[0][id[i][0]]++; } a[0].m[0][0]++; while(m--){ int x,y,z; Rd(x);Rd(y);Rd(z); z--; cnt[id[x][z]]++; a[0].m[id[x][z]][id[y][0]]++; } ll Max=K*3,ans=0; int len=0; while((1LL<<len)<=Max)len++; for(int i=1;i<len;i++) a[i]=a[i-1]*a[i-1]; c.m[0][0]=1; for(int i=len-1;i>=0;i--){ b=c*a[i]; if(check()){ ans|=(1LL<<i); memcpy(c.m[0],b.m[0],sizeof(b.m[0])); } } ans++; if(ans>=Max)ans=-1; cout<<ans<<endl; return 0;}
- BZOJ4386: [POI2015]Wycieczki
- BZOJ4386[POI2015] Wycieczki
- BZOJ4386: [POI2015]Wycieczki
- bzoj 4386: [POI2015]Wycieczki 矩阵乘法&倍增
- POI2015 题解
- bzoj 3747: [POI2015]Kinoman
- bzoj3747【POI2015】Kinoman
- [BZOJ3747] [POI2015]Kinoman
- 【POI2015】【BZOJ4378】Logistyka
- BZOJ 3747: [POI2015]Kinoman
- BZOJ 3748: [POI2015]Kwadraty
- BZOJ4378: [POI2015]Logistyka
- BZOJ4379: [POI2015]Modernizacja autostrady
- BZOJ4381: [POI2015]Odwiedziny
- BZOJ4383: [POI2015]Pustynia
- 【bzoj4378】[POI2015]Logistyka
- 【bzoj4380】[POI2015]Myjnie
- [bzoj4378][POI2015]Logistyka
- 请列举出你所知道的所有通讯协议,并阐述他们的应用场合?
- Merge Sorted Array | LeetCode
- 设计模式之观察者模式
- (八)Servlet就是这样-JDBC及相关
- Android缓存框架 DiskLruCache
- BZOJ4386[POI2015] Wycieczki
- linux-2.6.29 linux设备驱动归纳总结 目录
- 大数据以及Hadoop相关概念介绍
- XSS绕过的常见方法
- 基于改进DTC的数字水印Java实现(应用于移动端Android)------阿冬专栏
- JavaScript的原型系统是怎样构建起来的
- 实战-Fluxion与wifi热点伪造、钓鱼、中间人攻击、wifi破解
- Jsp之常用的内置对象
- 安卓检测升级(更新)