[Luogu P3597] [BZOJ 4386] [POI2015]WYC
阿新 • • 發佈:2018-11-25
洛谷傳送門
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);
}