結果
問題 | No.95 Alice and Graph |
ユーザー |
![]() |
提出日時 | 2015-08-30 19:40:33 |
言語 | C++11 (gcc 13.3.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 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 9 RE * 5 |
ソースコード
#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 1int main(int argc, char *argv[]){ios::sync_with_stdio(false);auto obj = new AliceAndGraph();obj->solve();delete obj;return 0;}#endif