AOJ2585 一日乗車券
問題ページ 1 Day Passport | Aizu Online Judge
考えたこと
- とりあえず入力で何がくるのかちゃんと読む
- 会社の数の制約が小さい
- dp[S] = (会社の集合Sを乗り放題にするために必要な最小コスト) を求めておく
- これは簡単なbitDPでできてO(2^KP)
- 会社の集合Sが乗り放題のときに s->t に行くかかる時間がh以下の最小のコストを求めたい
- d[i][j] = (頂点iまでに時間jかかったときの最小コスト) として拡張dijkstra
- 全ての集合Sに対して拡張dijkstraをするのでO(2^KMlogNH) になる
- 計算量が問題なさそうなので出すと通った
典型詰め合わせセットみたいな問題
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; #define int ll using VI = vector<int>; using VVI = vector<VI>; using PII = pair<int, int>; #define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i) #define REP(i, n) FOR(i, 0, n) #define ALL(x) x.begin(), x.end() #define PB push_back const ll LLINF = (1LL<<60); const int INF = (1LL<<30); const int MOD = 1000000007; template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); } template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); } template <typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; } template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); } template<class S,class T> ostream &operator <<(ostream& out,const pair<S,T>& a){ out<<'('<<a.first<<','<<a.second<<')'; return out; } template<class T> ostream &operator <<(ostream& out,const vector<T>& a){ out<<'['; REP(i, a.size()) {out<<a[i];if(i!=a.size()-1)out<<',';} out<<']'; return out; } int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}; struct edge { int to, cost, time, com; }; vector<edge> g[105]; int dp[1<<8], ticket[1<<8], fee[1<<8]; int d[105][30]; signed main(void) { cin.tie(0); ios::sync_with_stdio(false); while(true) { int n, m, h, k; cin >> n >> m >> h >> k; if(!n) break; REP(i, 1<<k) dp[i] = ticket[i] = fee[i] = 0; REP(i, n) g[i].clear(); REP(i, m) { int a, b, c, h, r; cin >> a >> b >> c >> h >> r; a--, b--; g[a].PB({b, c, h, r-1}); g[b].PB({a, c, h, r-1}); } int s, t; cin >> s >> t; s--, t--; int p; cin >> p; REP(i, p) { int l; cin >> l >> fee[i]; REP(j, l) { int com; cin >> com; com--; ticket[i] |= 1<<com; } } REP(i, 1<<k) dp[i] = INF; dp[0] = 0; REP(i, 1<<k) REP(j, p) chmin(dp[i | ticket[j]], dp[i] + fee[j]); int ans = INF; REP(i, 1<<k) { // iの会社はただで使えるとする int ret = dp[i]; REP(j, 105) REP(l, 30) d[j][l] = INF; d[s][0] = 0; priority_queue<VI, VVI, greater<VI>> que; que.push({d[s][0], s, 0}); while(que.size()) { VI v = que.top(); que.pop(); if(v[1] == t) break; for(edge e: g[v[1]]) { int n_cost = d[v[1]][v[2]] + (i & 1 << e.com ? 0 : e.cost); if(v[2] + e.time <= h && d[e.to][v[2]+e.time] > n_cost) { d[e.to][v[2]+e.time] = n_cost; que.push({d[e.to][v[2]+e.time], e.to, v[2]+e.time}); } } } int mi = INF; REP(j, h+1) chmin(mi, d[t][j]); chmin(ans, ret+mi); } if(ans == INF) cout << -1 << endl; else cout << ans << endl; } return 0; }