[CF576D]Flights for Regular Customers

題目大意:有一張$n$個點$m$條邊的有向圖,第$i$條邊有個權值$d_i$表示至少要走$d_i$條邊才能夠通過這條邊(可重複),問從點$1$到點$n$最少通過幾條邊(重複算屢次),無解輸出$-1$。$n,m\leqslant150,d_i\leqslant 10^9$ios

題解:按$d_i$排序,一條條加入轉移矩陣,能夠用鄰接矩陣算出走剛好$k$次能夠到達的位置。能夠發現,在一個行的轉移矩陣下,若點$1$能夠走到點$n$,最多走$n-1$步。因而能夠先暴力走$n-1$次,若還不能到達$n$,就用矩陣快速冪計算。複雜度$O(n^4m(\log_2 d+n))$。能夠令一個向量表示點$1$能夠到達的點,就變成向量乘矩陣,複雜度少一個$n$,已經能夠經過了。也能夠用$\mathrm{bitset}$優化乘法,複雜度$O(\dfrac{n^3m(\log_2d+n)}{\omega})$優化

卡點:spa

 

C++ Code:blog

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <bitset>
const int maxn = 160;
typedef std::bitset<maxn> B8;

int n, m;
struct Matrix {
	B8 s[maxn];
	Matrix() { for (int i = 0; i < n; ++i) s[i].reset(); }
	Matrix operator * (const Matrix &rhs) {
		Matrix res;
		for (int i = 0; i < n; ++i)
			for (int j = 0; j < n; ++j)
				if (s[i][j]) res.s[i] |= rhs.s[j];
		return res;
	}
} base;
B8 operator * (const B8 &lhs, const Matrix &rhs) {
	B8 res; res.reset();
	for (int i = 0; i < n; ++i)
		if (lhs[i]) res |= rhs.s[i];
	return res;
}
B8 R;

struct Edge {
	int a, b, d;
	inline bool operator < (const Edge &rhs) const { return d < rhs.d; }
} e[maxn];

int check(int N) {
	for (int i = 1; i <= N; ++i) {
		R = R * base;
		if (R[n - 1]) return i;
	}
	return N + 1;
}
void pw(int p) {
	Matrix b = base;
	for (; p; p >>= 1, b = b * b) if (p & 1) R = R * b;
}
int solve() {
	int p = 1, res = 0;
	for (; p <= m && e[p].d == 0; ++p) base.s[e[p].a - 1].set(e[p].b - 1);
	if (p == 1) return 0;
	R.set(0);
	for (int t, o; p <= m; ++p) {
		t = e[p].d - e[p - 1].d;
		if (t <= n) {
			o = check(t);
			if (o > t) res += t;
			else return res + o;
		} else {
			o = check(n);
			if (o > n) pw(t - n), res += t;
			else return res + o;
		}
		base.s[e[p].a - 1].set(e[p].b - 1);
	}
	int o = check(n);
	if (o > n) return 0;
	return res + o;
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	std::cin >> n >> m;
	for (int i = 1; i <= m; ++i)
		std::cin >> e[i].a >> e[i].b >> e[i].d;
	std::sort(e + 1, e + m + 1);
	int ans = solve();
	if (!ans) std::cout << "Impossible\n";
	else std::cout << ans << '\n';
	return 0;
}
相關文章
相關標籤/搜索