DP[どこを巡った][今どこ] = 最短時間
O(2^N * N)
前もって全点間最短距離を計算しておく。
const int V = 50 + 5;
lli g[V][V];
const lli inf = 604800 * 5;
struct S {
lli begin, end, dur;
};
S store[V];
const int M = 16;
const int BIT = 1 << M;
const lli L = 604800;
class TravellingPurchasingMan {
public:
int maxStores(int N, vector <string> inter, vector <string> R)
{
fill(&g[0][0], &g[V - 1][V - 1] + 1, inf);
for (int i = 0; i < R.size(); ++i) {
istringstream iss(R[i]);
lli a, b, len;
iss >> a >> b >> len;
g[a][b] = g[b][a] = min(g[a][b], len);
}
for (int i = 0; i < inter.size(); ++i) {
istringstream iss(inter[i]);
iss >> store[i].begin >> store[i].end >> store[i].dur;
}
for (int i = 0; i < N; ++i) {
g[i][i] = 0;
}
for (int k = 0; k < N; ++k) {
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
}
}
}
const int m = inter.size();
const int BIT = 1 << M;
static lli dp[BIT][M];
fill(&dp[0][0], &dp[BIT - 1][M - 1] + 1, inf);
for (int i = 0; i < m; ++i) {
if (g[N - 1][i] <= store[i].end) {
dp[1 << i][i] = g[N - 1][i];
}
}
const int B = 1 << m;
for (int bit = 0; bit < B; ++bit) {
for (int curr = 0; curr < m; ++curr) {
if (bit & (1 << curr)) {
unless (dp[bit][curr] <= store[curr].end) continue;
for (int next = 0; next < m; ++next) {
unless (bit & (1 << next)) {
lli p = max(store[curr].begin, dp[bit][curr]) + store[curr].dur;
lli c = p + g[curr][next];
lli& ref = dp[bit | (1 << next)][next];
ref = min(ref, c);
}
}
}
}
}
int mx = 0;
for (int bit = 0; bit < BIT; ++bit) {
int bc = __builtin_popcount(bit);
for (int i = 0; i < M; ++i) {
if (dp[bit][i] <= store[i].end) mx = max(mx, bc);
}
}
return mx;
}