传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2516
【题解】
状压dp。
$f_{sta,i}$表示状态为sta,当前在第i层的最小花费时间。状态是个三进制表示,0代表没进过电梯;1代表在电梯里;2表示进过电梯,出来了。
然后考虑当前状态转移出去即可。复杂度$O(Cas * 3^n * nm)$,成功垫底。
据说用2个二进制可以更快(逃
# include <vector> # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> // # include <bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int M = 5e5 + 10; const int mod = 1e9+7, inf = 1e9; const int STATUS_SIZE = 59049 + 5; int n, m, fir, bin[12]; int f[STATUS_SIZE][22], s[12]; struct pa { int t, a, b; pa() {} pa(int t, int a, int b) : t(t), a(a), b(b) {} }p[12]; vector<int> ps; # define abs(x) ((x) > 0 ? (x) : -(x)) # define bit(x, i) (((x) / bin[i]) % 3) # define dist(i, j) (abs(ps[j-1] - ps[i-1])) inline int getid(int x) { return lower_bound(ps.begin(), ps.end(), x) - ps.begin() + 1; } inline void gmin(int &a, int b) { if(b < a) a = b; } inline void sol() { cin >> n >> fir; ps.clear(); ps.push_back(fir); for (int i=1; i<=n; ++i) { scanf("%d%d%d", &p[i].t, &p[i].a, &p[i].b); ps.push_back(p[i].a); ps.push_back(p[i].b); } sort(ps.begin(), ps.end()); ps.erase(unique(ps.begin(), ps.end()), ps.end()); for (int i=1; i<=n; ++i) { p[i].a = getid(p[i].a); p[i].b = getid(p[i].b); } fir = getid(fir); m = ps.size(); for (int sta=0; sta<bin[n]; ++sta) for (int i=1; i<=m; ++i) f[sta][i] = inf; for (int i=1; i<=m; ++i) f[0][i] = dist(i, fir); for (int sta=0; sta<bin[n]; ++sta) { for (int i=1; i<=m; ++i) { for (int j=1; j<=n; ++j) { if(bit(sta, j-1) == 1) gmin(f[sta+bin[j-1]][p[j].b], max(f[sta][i] + dist(p[j].b, i), p[j].t)); else if(bit(sta, j-1) == 0) gmin(f[sta+bin[j-1]][p[j].a], max(f[sta][i] + dist(p[j].a, i), p[j].t)); } } } int ans = inf; for (int i=1; i<=m; ++i) gmin(ans, f[bin[n]-1][i]); cout << ans << endl; } int main() { bin[0] = 1; for (int i=1; i<=10; ++i) bin[i] = bin[i-1]*3; int T; cin >> T; while(T--) sol(); return 0; }