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;
- }