WYC
题目大意
给你一个有向图,让你求图中的kkk短路(非简单路径)
输入样例#
6 6 11
1 2 1
2 3 2
3 4 2
4 5 1
5 3 1
4 6 3
输出样例#1
4
数据范围
1⩽n⩽40,1⩽m⩽1000,1⩽k⩽10181\leqslant n\leqslant 40,1\leqslant m\leqslant 1000,1\leqslant k\leqslant 10^{18}1⩽n⩽40,1⩽m⩽1000,1⩽k⩽1018
1⩽u,v⩽n,u≠v,1⩽c⩽31\leqslant u,v\leqslant n,u\neq v,1\leqslant c\leqslant 31⩽u,v⩽n,u=v,1⩽c⩽3
解题思路
边长和点数很小,我们可以考虑拆点+++矩阵乘法
我们得出fi=A2if_i=A^{2^i}fi=A2i
我们加一个计数点,所有整点都连向它,它再连一个自环
这样0就可以计算长度小于i的路线会保留下来
我们再倍增判断求k短路
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define p(x, y) ((x) * 3 + (y) + 1)
using namespace std;
ll n, m, k, x, y, z, w, nn, ans, pw[100];
struct matrix
{ll a[150][150];
}f[100], g, gg;
matrix jc(matrix &a, matrix &b)
{matrix c;memset(c.a, 0, sizeof(c.a));for (ll i = 0; i < nn; ++i)for (ll j = 0; j < nn; ++j)for (ll k = 0; k < nn; ++k)c.a[i][j] += a.a[i][k] * b.a[k][j];//矩阵乘法return c;
}
bool check(matrix a)
{ll sum = 0;for (ll i = 0; i < n; ++i){sum += a.a[p(i, 0)][0] - 1;//因为每个点都有一种方案直接到0,无边if (k <= sum) return 1;}return 0;
}
int main()
{scanf("%lld%lld%lld", &n, &m, &k);nn = n * 3 + 1;f[0].a[0][0] = 1;for (ll i = 0; i < n; ++i){f[0].a[p(i, 2)][p(i, 1)] = 1;//拆点f[0].a[p(i, 1)][p(i, 0)] = 1;f[0].a[p(i, 0)][0] = 1;gg.a[p(i, 0)][p(i, 0)] = 1;}for (ll i = 1; i <= m; ++i){scanf("%lld%lld%lld", &x, &y, &z);x--;y--;f[0].a[p(x, 0)][p(y, z - 1)]++;}pw[0] = 1;while(++w){if (w > 60){printf("-1");return 0;}pw[w] = pw[w - 1] * 2;f[w] = jc(f[w - 1], f[w - 1]);//计算fif (check(f[w])) break;}while(w--){g = jc(gg, f[w]);if (!check(g))//判断当前是否在k短路内ans += pw[w], gg = g;//计算结果}printf("%lld", ans);return 0;
}