#include <bits/stdc++.h>

using namespace std;

template< typename T >
struct edge {
  int src, to;
  T cost;

  edge(int to, T cost) : src(-1), to(to), cost(cost) {}

  edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}

  edge &operator=(const int &x) {
    to = x;
    return *this;
  }

  operator int() const { return to; }
};

template< typename T >
using Edges = vector< edge< T > >;
template< typename T >
using WeightedGraph = vector< Edges< T > >;
using UnWeightedGraph = vector< vector< int > >;
template< typename T >
using Matrix = vector< vector< T > >;


template< typename G >
struct LowLink {
  const G &g;
  vector< int > used, ord, low;
  vector< int > articulation;
  vector< pair< int, int > > bridge;

  LowLink(const G &g) : g(g), used(g.size()), ord(g.size()), low(g.size()) {}

  int build(int idx = 0, int k = 0, int par = -1) {
    used[idx] = true;
    ord[idx] = k++;
    low[idx] = ord[idx];
    bool is_articulation = false;
    int cnt = 0, ordmax = k;
    for(auto &to : g[idx]) {
      if(!used[to]) {
        ++cnt;
        ordmax = build(to, ordmax, idx);
        low[idx] = min(low[idx], low[to]);
        is_articulation |= ~par && low[to] >= ord[idx];
        if(ord[idx] < low[to]) bridge.emplace_back(idx, to);
      } else if(to != par) {
        low[idx] = min(low[idx], ord[to]);
      }
    }
    is_articulation |= par == -1 && cnt > 1;
    if(is_articulation) articulation.push_back(idx);
    return ordmax;
  }
};


int main() {
  int V, E;
  scanf("%d %d", &V, &E);
  UnWeightedGraph g(V);
  for(int i = 0; i < E; i++) {
    int x, y;
    scanf("%d %d", &x, &y);
    g[x].push_back(y);
    g[y].push_back(x);
  }
  LowLink< UnWeightedGraph > lowlink(g);
  lowlink.build();
  sort(lowlink.articulation.begin(), lowlink.articulation.end());
  for(auto &v : lowlink.articulation) printf("%d\n", v);
}


#include <iostream>
#include <vector>

using namespace std;

int dfs(auto& nodes, int current_index, int parent_index, int& time) {
    int children = 0;
    
    auto& current_node = nodes[current_index];
    current_node.time = time;
    current_node.low = time;
    
    for (auto adjacent_index : current_node.adjacent) {
        if (adjacent_index == parent_index) {
            continue;
        }
        
        auto& adjacent_node = nodes[adjacent_index];
        if (adjacent_node.time) {
            current_node.low = min(adjacent_node.time, current_node.low);
        } else {
            ++children;
            dfs(nodes, adjacent_index, current_index, ++time);
            
            if (current_node.time <= adjacent_node.low) {
                current_node.is_articulation_point = true;
            }
            
            current_node.low = min(adjacent_node.low, current_node.low);
        }
    }
    
    return children;
}

int main() {
    int n, m;
    
    cin >> n >> m;
    if (n == 0 || m == 0) {
        return 0;
    }
    
    struct node {
        int time{0};
        int low{0};
        bool is_articulation_point{false};
        vector<int> adjacent;
    };
    
    vector<node> nodes(n);
    for (int i = 0; i < m; ++i) {
        int from, to;
        cin >> from >> to;
        nodes[from].adjacent.push_back(to);
        nodes[to].adjacent.push_back(from);
    }
    
    int time = 0;
    nodes[0].is_articulation_point = dfs(nodes, 0, -1, ++time) > 1;
    
    for (int i = 0; i < nodes.size(); ++i) {
        if (nodes[i].is_articulation_point) {
            cout << i << endl;
        }
    }
    
    return 0;
}
