#include 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> dist(N, vector(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> dp(1<<(K+1), vector(K+1)); auto calcCost = [&](const vector &s) { int sz = s.size(); REP(i,1< j への到達コストを計算 { // s[i] に未到達なら飛ばす if (dp[bit][i] == inf) continue; if ( !(bit & (1< 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<solve(); delete obj; return 0; } #endif