版权声明:欢迎转载蒟蒻博客,但请注明出处: https://blog.csdn.net/LPA20020220/article/details/84348331
洛谷传送门
BZOJ传送门
题目描述
给定一张 个点 条边的带权有向图,每条边的边权只可能是 , , 中的一种。将所有可能的路径按路径长度排序,请输出第 小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点。
输入输出格式
输入格式:
第一行包含三个整数 。接下来 行,每行三个整数 ,表示从 出发有一条到 的单向边,边长为 。可能有重边。
输出格式:
包含一行一个正整数,即第 短的路径的长度,如果不存在,输出 。
输入输出样例
输入样例#1:
6 6 11
1 2 1
2 3 2
3 4 2
4 5 1
5 3 1
4 6 3
输出样例#1:
4
说明
给定一张 个点 条边的带权有向图,每条边的边权只可能是 , , 中的一种。
将所有可能的路径按路径长度排序,请输出第 小的路径的长度,注意路径不一定是简单路径,即可以重复走同一个点。
解题分析
明显是矩阵快速幂统计路径个数。 这里类似用倍增的方法, 预处理出转移 次后的矩阵, 再从大到小尝试加回来。
统计长度 的路径个数, 只需要添加每个点到 节点, 以及 的边即可。 但因为第一次未转移的时候多算了一次, 所以注意减一。
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 125
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int n, m, bd;
ll k, ans;
struct Matrix {ll mat[MX][MX];} mp[66], buf, now;
IN Matrix operator * (const Matrix &x, const Matrix &y)
{
Matrix ret;
R int i, j, k;
for (i = 0; i <= bd; ++i)
for (j = 0; j <= bd; ++j)
{
ret.mat[i][j] = 0;
for (k = 0; k <= bd; ++k)
ret.mat[i][j] += x.mat[i][k] * y.mat[k][j];
}
return ret;
}
IN bool count(const Matrix &tar)
{
ll ret = 0;
for (R int i = 1; i <= n; ++i)
if ((ret += tar.mat[i][0] - 1) >= k) return true;
return false;
}
IN ll calc(const Matrix &tar)
{
ll ret = 0;
for (R int i = 1; i <= n; ++i)
ret += tar.mat[i][0] - 1;
return ret;
}
int main(void)
{
int a, b, c, cur;
in(n), in(m), in(k); bd = n * 3;
mp[0].mat[0][0] = 1;
for (R int i = 1; i <= n; ++i)
{
mp[0].mat[i][0] = 1;
mp[0].mat[i][i + n] = 1;
mp[0].mat[i + n][i + 2 * n] = 1;
}
for (R int i = 1; i <= m; ++i)
{
in(a), in(b), in(c);
mp[0].mat[a + (c - 1) * n][b]++;
}
for (cur = 1; ; ++cur)
{
if (cur > 64) return puts("-1"), 0;
mp[cur] = mp[cur - 1] * mp[cur - 1];
if (count(mp[cur])) break;
}
for (R int i = 0; i <= bd; ++i) now.mat[i][i] = 1;
for (--cur; ~cur; --cur)
{
buf = now * mp[cur];
if (!count(buf)) now = buf, ans += 1ll << cur;
}
printf("%lld", ans);
}