CodeForces576DFlights for Regular Customers

Posted youthrhythms

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces576DFlights for Regular Customers相关的知识,希望对你有一定的参考价值。

题目链接

点击打开链接

题目解法

考虑枚举最优状态是哪些边解锁了,哪些边没有。这样真的有 (2^n) 种情况吗?并不是的。将所有边按照解锁需要走过边的数量排序。解锁边的顺序必然是排好序的这样。所以考虑只解锁前 (i) 条边,走到 (n) 的最短距离是多少。

所以我们可以这样:每次枚举新解锁了哪一条边,如果当前边需要走 (i) 步才能解锁,那么看走 (i) 条边并解锁这个边后可以到哪些点,用那些点跑一边多源 dfs 寻找到终点的最短路,更新答案即可。

然而这时间复杂度 (mathcal O(n^3mlog n)) 并不能过去。瓶颈是矩阵快速幂。由于矩阵是0/1 矩阵,所以使用bitset优化即可。比较无脑的bitset可以维护矩阵的行和列,维护两个bitset数组,这样比较方便写。当然也可以只维护一个bitset,这样难理解,而且非常非常没必要。

总结

  • bitset 优化0/1矩阵的乘法。
  • 解锁顺序可以去掉一些边的解锁状态。

代码

#include <cstdio>
#include <bitset>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int NM = 155;
const ll infll = 0x3f3f3f3f3f3f3f3fll;
typedef bitset<150> bt;
int n, m;
struct Edge {
	int u, v, w;
	inline bool operator < (const Edge &d) const { return w < d.w; }
} eg[NM];
struct Mat {
	bt A[150];
	inline bt & operator [] (const int i) { return A[i]; }
	inline const bt & operator [] (const int i) const { return A[i]; }
	//因为 Mat * 不能保存 const Mat * 的东西
	//所以必须有一种返回 const Mat * 的调用方法 
} A;
bt operator * (const Mat &A, const bt &B) {
	static bt ret;
	for (int i = 0; i < n; ++i) ret[i] = (A[i] & B).any();
	return ret;
}
Mat operator * (const Mat &A, const Mat &B) {
	static Mat ret;
	for (int i = 0; i < n; ++i) ret[i].reset();
	for (int i = 0; i < n; ++i)
		for (int j = 0; j < n; ++j)
			if (A[i][j]) ret[i] |= B[j];
	return ret;
}
void ksm(bt &A, Mat B, int c) {
	for (; c; c >>= 1, B = B * B)
		if (c & 1) A = B * A;
}
bt go;
queue<int> Q;
ll dis[NM];
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; ++i) {
		scanf("%d%d%d", &eg[i].u, &eg[i].v, &eg[i].w);
		--eg[i].u, --eg[i].v;
	}
	sort(eg + 1, eg + m + 1);
	go[0] = 1;
	ll ans = infll;
	for (int i = 1, t = 0; i <= m; ++i) {
		if (eg[i].w >= ans) break ;
		if (eg[i].w != t) ksm(go, A, eg[i].w - t);
		t = eg[i].w;
		A[eg[i].v][eg[i].u] = 1;
		for (int j = 0; j < n; ++j)
			if (go[j]) Q.push(j), dis[j] = 0;
			else dis[j] = infll;
		while (Q.size()) {
			int u = Q.front();
			Q.pop();
			for (int j = 0; j < n; ++j)
				if (A[j][u] && dis[j] == infll) {
					dis[j] = dis[u] + 1;
					Q.push(j);
				}
		}
		ans = min(ans, t + dis[n - 1]);
	}
	if (ans == infll) printf("Impossible
");
	else printf("%lld
", ans);
	return 0;
}

以上是关于CodeForces576DFlights for Regular Customers的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 576D Flights for Regular Customers 矩阵快速幂+DP

Codeforces 576D. Flights for Regular Customers(倍增+floyd+bitset优化)

Codeforces Round #576 (Div. 2) B - Water Lily

Codeforces Round #576 (Div. 2) D - Welfare State

Codeforces Round #576 (Div. 2) D. Welfare State

codeforces 576c// Points on Plane// Codeforces Round #319(Div. 1)