結果
問題 | No.95 Alice and Graph |
ユーザー | codershifth |
提出日時 | 2015-08-30 19:40:33 |
言語 | C++11 (gcc 11.4.0) |
結果 |
RE
(最新)
AC
(最初)
|
実行時間 | - |
コード長 | 4,423 bytes |
コンパイル時間 | 1,665 ms |
コンパイル使用メモリ | 167,632 KB |
実行使用メモリ | 9,856 KB |
最終ジャッジ日時 | 2024-11-14 13:33:46 |
合計ジャッジ時間 | 4,892 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 225 ms
9,856 KB |
testcase_01 | AC | 40 ms
9,728 KB |
testcase_02 | AC | 40 ms
9,728 KB |
testcase_03 | AC | 9 ms
9,856 KB |
testcase_04 | AC | 322 ms
9,728 KB |
testcase_05 | AC | 254 ms
9,728 KB |
testcase_06 | AC | 315 ms
9,856 KB |
testcase_07 | AC | 39 ms
9,728 KB |
testcase_08 | RE | - |
testcase_09 | RE | - |
testcase_10 | RE | - |
testcase_11 | RE | - |
testcase_12 | RE | - |
testcase_13 | AC | 439 ms
9,728 KB |
ソースコード
#include <bits/stdc++.h> typedef long long ll; typedef unsigned long long ull; #define FOR(i,a,b) for(int (i)=(a);i<(b);i++) #define REP(i,n) FOR(i,0,n) #define RANGE(vec) (vec).begin(),(vec).end() using namespace std; class AliceAndGraph { public: void solve(void) { const int inf = (1<<25); int N,M,K; cin>>N>>M>>K; vector<vector<int>> dist(N, vector<int>(N, inf)); REP(_,M) { int u,v; cin>>u>>v; --u,--v; dist[u][v] = dist[v][u] = 1; } // // S2(k) = 1+2+2^2+...+2^(k-1) = 2^k-1 とすると // S2(1) + S2(2) + ... + S2(k-1) = S2(k) - k < S2(k) // // なので S2(k) の大きい物から優先的に回るとよい // // 最短経路を求めておく // O(N^3) REP(k,N) REP(i,N) REP(j,N) dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]); // // パス上のノードのコインを獲得するが v から u へのパスが一つではないので // どのパスを選ぶのがよいか探索しなくてはいけない。 // (基本的には中間ノードで出現する番号が最も大きいパスを選べばよいが、 // それはパスを選んで通過してみないとわからない。) // // そこで以下のような bit DP を考える。 // // 最大到達可能なノード数は K 個なので // N-1,N-2,... の順で到達候補ノード集合 S (size(S) <= K+1 0 ノードを含む分 +1) // にノードを追加して実際に cost K 以内で到達が可能か試す。 // // S = {N-1,0} ... ok // S = {N-1,N-2,0} ... NG // S = {N-1,N-3,0} ... ok // S = {N-1,N-3,N-4,0} ... ok // : // S _{N-1,N-3,N-4,...,0} ... answer // // dp[bit][i] := 訪問ノードが bit で現在地が i のときの最小コスト vector<vector<int>> dp(1<<(K+1), vector<int>(K+1)); auto calcCost = [&](const vector<int> &s) { int sz = s.size(); REP(i,1<<sz) fill(RANGE(dp[i]), inf); // 初期化 dp[1][0] = 0; // 0 をスタート地点にして全て回る for (int bit = 1; bit < (1<<sz); ++bit) { REP(i,sz) // i -> j への到達コストを計算 { // s[i] に未到達なら飛ばす if (dp[bit][i] == inf) continue; if ( !(bit & (1<<i)) ) continue; // 未到達なもの毎にチェック REP(j,sz) { // 到達済みは飛ばす if (bit & (1<<j)) continue; int next = bit | (1<<j); dp[next][j] = min(dp[next][j], dp[bit][i] + dist[s[i]][s[j]]); } } } int ans = inf; REP(i,sz) // 終端位置毎にチェック ans = min(dp[(1<<sz)-1][i], ans); return ans; }; vector<int> S; S.push_back(0); // O(N*2^K) for (int u = N-1; u > 0; --u) { // 候補ノード u を追加してみて K 以内に到達可能か試す。 S.push_back(u); if ( calcCost(S) > K ) S.pop_back(); // だめだったら候補から外す。 // 次の追加で S の容量を超えたら終了 if (S.size()+1 > (size_t)K+1) break; } // 獲得 coin の枚数を計算 ll ans = 0; for (auto i : S) ans += (1LL<<i)-1; cout<<ans<<endl; } }; #if 1 int main(int argc, char *argv[]) { ios::sync_with_stdio(false); auto obj = new AliceAndGraph(); obj->solve(); delete obj; return 0; } #endif