Cod sursa(job #3324287)

Utilizator mircea_007Mircea Rebengiuc mircea_007 Data 21 noiembrie 2025 22:03:11
Problema Santa Scor 10
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 6.64 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();
  int m = (int)edges.size();

  vec<vec<int>> ret; {
    vec<bool> viz(n, false);
    vec<bool> edge_viz(m, false);
    vec<int> edge_stack;
    
    auto dfs = [&]( auto &&self, int u, int p ) -> void {
      viz[u] = true;
      for( int edge : adj[u] ){
        if( edge_viz[edge] ) continue;
        int v = other( edges[edge], u );
        
        if( !viz[v] ){
          edge_stack.push_back( edge );
          self( self, v, u );
          if( !edge_stack.empty() && edge_stack.back() == edge ){
            ret.emplace_back( 1, edge );
            edge_stack.pop_back();
            edge_viz[edge] = true;
          }
        }else if( v != p ){
          ret.emplace_back( 1, edge );
          edge_viz[edge] = true;

          do{
            ret.back().push_back( edge_stack.back() );
            edge_viz[ret.back().back()] = true;
            edge_stack.pop_back();
          }while( !has( edges[ret.back().back()], v ) );
        }
      }
    };

    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 ) {
  int p2 = (1 << n);
  vec<vec<int>> prev(n, vec<int>(p2, NIL));
  prev[src][1 << src] = src; // fake, ma rog..

  edges.insert( edges.end(), edges.begin(), edges.end() );
  for( int i = (int)edges.size() / 2; i < (int)edges.size(); i++ )
    std::swap( edges[i].first, edges[i].second );

  for( int mask = 0; mask < p2; mask++ ){
    for( auto [a, b]: edges ){
      if( !(mask & (1 << a)) || (mask & (1 << b)) ) continue;
      if( prev[a][mask] == NIL ) continue;
      prev[b][mask | (1 << b)] = a;
    }
  }

  // std::cerr << "n = " << n << std::endl;
  // for( auto [a, b]: edges )
  //   std::cerr << "(" << a << ", " << b << ")\n";
  // std::cerr << "src = " << src << ", dest = " << dest << std::endl;

  int last = dest;
  if( last == NIL ){
    for( int i = 0; i < n; i++ )
      if( i != src && prev[i][p2 - 1] != NIL )
        last = i;
  }

  if( last == NIL || prev[last][p2 - 1] == NIL ) return {};

  int mask = p2 - 1;
  vec<int> ret(1, 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() );
  return ret;
}

vec<int> get_path( std::ifstream &fin, std::ofstream &fout ) {
  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--;

  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, fout );
  if( path.empty() ){
    fout << "No chance\n";
    return 0;
  }

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