Cod sursa(job #3324306)

Utilizator mircea_007Mircea Rebengiuc mircea_007 Data 21 noiembrie 2025 23:12:57
Problema Santa Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 7.56 kb
#include <fstream>
#include <iostream>
#include <cassert>

#include <algorithm>
#include <vector>

#include <queue>
#include <map>

constexpr int INF = 1e9;
constexpr int NIL = -1;

template<class T> using vec = std::vector<T>;
bool has( const std::pair<int, int> p, int x ) { return p.first == x || p.second == x; }
int other( const std::pair<int, int> p, int x ) { assert( has( p, x ) ); return p.first + p.second - x; }
int common( const std::pair<int, int> A, const std::pair<int, int> B ) {
  return A.first * has( B, A.first ) + A.second * has( B, A.second );
}

vec<vec<int>> get_biconex( const vec<vec<int>> &adj, const vec<std::pair<int, int>> &edges ) {
  int n = (int)adj.size();

  vec<vec<int>> ret; {
    vec<bool> viz(n, false);
    vec<int> edge_stack;

    int time = 0;
    vec<int> t(n, 0);
    auto dfs = [&]( auto &&self, int u, int p ) -> int {
      t[u] = time++;
      int reach = t[u];
      
      viz[u] = true;
      for( int edge : adj[u] ){
        int v = other( edges[edge], u );
        
        if( !viz[v] ){
          edge_stack.push_back( edge );
          int reach_v = self( self, v, u );
          reach = std::min( reach, reach_v );

          if( reach_v >= t[u] ){
            ret.emplace_back();
            do{
              ret.back().push_back( edge_stack.back() );
              edge_stack.pop_back();
            }while( ret.back().back() != edge );
          }
        }else if( v != p && t[v] < t[u] ){
          reach = std::min( reach, t[v] );
          edge_stack.push_back( edge );
        }
      }

      return reach;
    };

    for( int i = 0; i < n; i++ )
      if( !viz[i] ){
        dfs( dfs, i, i );
        assert( edge_stack.empty() );
      }
  }
  
  return ret;
}

vec<int> hamilton( int n, vec<std::pair<int, int>> edges, int src, int dest ) {
  if( n == 1 ) return vec<int>(1, src);
  if( n == 2 ) return vec<int>({ src, other( edges[0], src ) });
  
  // truc: src si dest devin n - 1, n - 2
  bool rem_last = false;
  if( dest == NIL ){
    for( int i = 0; i < n; i++ )
      edges.emplace_back( i, n );
    dest = n++;
    rem_last = true;
  }
  
  vec<int> encode(n), decode(n); {
    for( int i = 0; i < n; i++ )
      encode[i] = decode[i] = i;

    int x = decode[n - 1];
    std::swap( encode[src], encode[x] );
    std::swap( decode[encode[src]], decode[encode[x]] );

    int y = decode[n - 2];
    std::swap( encode[dest], encode[y] );
    std::swap( decode[encode[dest]], decode[encode[y]] );

    src = encode[src];
    dest = encode[dest];
    assert( src == n - 1 && dest == n - 2 );
  }
  
  vec<vec<int>> adj(n); {
    for( auto [a, b]: edges ){
      adj[encode[a]].push_back( encode[b] );
      adj[encode[b]].push_back( encode[a] );
    }
  }

  int small = n - 2;
  int small_p2 = (1 << small);
  vec<vec<int>> prev(small, vec<int>(small_p2, NIL));
  for( int v : adj[src] )
    if( v < small )
      prev[v][1 << v] = src;

  vec<int> bit_adj(small);
  for( int i = 0; i < small; i++ )
    for( int j : adj[i] )
      if( j < small )
        bit_adj[i] |= (1 << j);

  for( int mask = 0; mask < small_p2; mask++ ){
    for( int a = 0; a < small; a++ ){
      if( !(mask & (1 << a)) ) continue;
      if( prev[a][mask] == NIL ) continue;

      int good_vec = (~mask & bit_adj[a]);
      while( good_vec ){
        int pb = good_vec & -good_vec;
        good_vec ^= pb;
        prev[31 ^ __builtin_clz( pb )][mask | pb] = a;
      }
    }
  }

  int last = NIL; {
    for( int v : adj[dest] )
      if( v < small && prev[v][small_p2 - 1] != NIL )
        last = v;
  }

  if( last == NIL ) return {};

  int mask = small_p2 - 1;
  vec<int> ret({ dest, last });
  while( ret.back() != src ){
    int P = prev[ret.back()][mask];
    mask &= ~(1 << ret.back());
    ret.push_back( P );
  }

  assert( (int)ret.size() == n );
  std::reverse( ret.begin(), ret.end() );
  for( int &u : ret ) u = decode[u];
  if( rem_last ) ret.pop_back();
  return ret;
}

vec<int> get_path( std::ifstream &fin ) {
  int n, m;
  fin >> n >> m;

  vec<std::pair<int, int>> edges;
  vec<vec<int>> adj(n); {
    for( int i = 0; i < m; i++ ){
      int a, b;
      fin >> a >> b;
      edges.emplace_back( --a, --b );
      adj[a].push_back( i );
      adj[b].push_back( i );
    }
  }

  int src, dest, path_begin;
  fin >> src >> dest >> path_begin;
  src--; dest--; path_begin--;

  if( src == dest ) {
    if( src != path_begin ) return {};
    return vec<int>(1, src);
  }

  vec<vec<int>> biconexe = get_biconex( adj, edges );
  vec<int> edge2bi(m); {
    for( int i = 0; i < (int)biconexe.size(); i++ )
      for( int u : biconexe[i] )
        edge2bi[u] = i;
  }

  vec<int> path; {
    vec<int> dist(n, +INF);
    vec<int> prev(n);
    std::queue<int> q({ src });
    dist[src] = 0;

    while( !q.empty() ){
      int u = q.front();
      q.pop();
      
      for( int edge : adj[u] ){
        int v = other( edges[edge], u );
        if( dist[u] + 1 < dist[v] ){
          dist[v] = 1 + dist[u];
          prev[v] = edge;
          q.push( v );
        }
      }
    }

    int u = dest;
    if( dist[u] >= +INF ) return {};
    while( u != src ){
      path.push_back( prev[u] );
      u = other( edges[prev[u]], u );
    }

    std::reverse( path.begin(), path.end() );
  }

  vec<int> bis(1, edge2bi[path[0]]);
  vec<int> transitions;
  for( int i = 1; i < (int)path.size(); i++ ){
    if( edge2bi[path[i - 1]] == edge2bi[path[i]] ) continue;
    bis.push_back( edge2bi[path[i]] );
    transitions.push_back( common( edges[path[i - 1]], edges[path[i]] ) );
  }

  assert( (int)bis.size() - 1 == (int)transitions.size() );

  auto bi_has = [&]( int bi, int u ) -> bool {
    bool ret = false;
    for( int edge : biconexe[bi] )
      ret |= has( edges[edge], u );
    return ret;
  };

  if( bi_has( bis.front(), path_begin ) ){
    transitions.insert( transitions.begin(), path_begin );
    transitions.push_back( NIL );
  }else if( bi_has( bis.back(), path_begin ) ){
    std::reverse( transitions.begin(), transitions.end() );
    std::reverse( bis.begin(), bis.end() );
    transitions.insert( transitions.begin(), path_begin );
    transitions.push_back( NIL );
  }else
    return {};

  assert( (int)bis.size() + 1 == (int)transitions.size() );
  assert( transitions.back() == NIL );

  auto viz_all = [&]( int bi, int src, int dest ) -> vec<int> {
    assert( bi_has( bi, src ) );
    assert( dest == NIL || bi_has( bi, dest ) );

    vec<int> wide;
    std::map<int, int> narrow; {
      for( int edge : biconexe[bi] ){
        auto [a, b] = edges[edge];
        narrow[a] = narrow[b] = 1;
      }

      for( auto &[key, val]: narrow ){
        val = (int)wide.size();
        wide.push_back( key );
      }
    }

    vec<std::pair<int, int>> narrow_edges;
    for( int edge : biconexe[bi] ){
      auto [a, b] = edges[edge];
      narrow_edges.emplace_back( narrow[a], narrow[b] );
    }

    vec<int> narrow_path = hamilton( (int)wide.size(), narrow_edges, narrow[src], (dest == NIL ? NIL : narrow[dest]) );
    for( int &u : narrow_path ) u = wide[u];
    return narrow_path; // acuma wide
  };

  vec<int> ret;
  for( int i = 0; i < (int)bis.size(); i++ ){
    vec<int> seg = viz_all( bis[i], transitions[i], transitions[i + 1] );
    if( seg.empty() ) return {};
    if( ret.empty() ){
      ret = seg;
      continue;
    }

    assert( ret.back() == seg.front() );
    ret.insert( ret.end(), seg.begin() + 1, seg.end() );
  }

  return ret;
}

int main() {
  std::ifstream fin("santa.in");
  std::ofstream fout("santa.out");

  vec<int> path = get_path( fin );
  if( path.empty() ){
    fout << "No chance\n";
    return 0;
  }

  fout << path.size() << '\n';
  for( int x : path )
    fout << x + 1 << ' ';
  fout << '\n';
  
  return 0;
}