Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++로 무방향 그래프에 주어진 크기의 독립 집합이 존재하는지 확인하는 방법


개념

주어진 무방향 그래프에서 크기 l의 독립 집합(independent set)이 존재하는지 확인하는 문제입니다. 독립 집합이 존재하면 'Yes'를 출력하고, 존재하지 않으면 'No'를 출력합니다. 여기서 독립 집합이란 집합에 속한 어떤 두 정점도 서로 직접 연결(간선으로 이어져 있지 않은)되어 있지 않은 정점들의 집합을 의미합니다.

입력 예시 1

L = 4,
graph = [[1, 0, 1, 0, 0],
[0, 1, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 1]];

출력

Yes

C++로 무방향 그래프에 주어진 크기의 독립 집합이 존재하는지 확인하는 방법

위 그래프는 크기 4의 독립 집합을 포함합니다. 정점 0, 1, 3, 4는 서로 직접 연결되어 있지 않으므로 출력은 'Yes'입니다.

입력 예시 2

L = 4,
graph = [[1, 1, 1, 0, 0],
[1, 1, 1, 0, 0],
[1, 1, 1, 1, 1],
[0, 0, 1, 1, 0],
[0, 0, 1, 0, 1]];

출력

No

C++로 무방향 그래프에 주어진 크기의 독립 집합이 존재하는지 확인하는 방법

위 그래프에는 크기 4의 독립 집합이 존재하지 않습니다. 따라서 출력은 'No'입니다.

풀이 방법

  • 먼저 sol 변수를 false 값으로 초기화합니다.
  • 주어진 그래프에서 크기 L이 될 수 있는 모든 정점 조합을 생성합니다.
  • 크기 l의 독립 집합을 찾으면 sol 값을 true로 변경한 뒤 탐색을 종료합니다.
  • 아직 찾지 못했다면 나머지 가능한 조합을 계속 검사합니다.
  • 마지막에 sol이 true이면 'Yes'를, 그렇지 않으면 'No'를 출력합니다.

이 방식은 가능한 모든 정점 조합을 검사하는 완전 탐색(brute force) 기법입니다. 정점 수가 n일 때 최악의 경우 O(2n × n²)의 시간이 소요될 수 있어 정점이 많은 그래프에는 비효율적이지만, 독립 집합 판정 문제의 핵심 원리를 명확하게 보여주는 접근 방식입니다.

C++ 구현 예제

// C++ 코드: 주어진 그래프가
// 크기 k의 독립 집합을 포함하는지 확인
#include <bits/stdc++.h>
using namespace std;
// 함수 원형 선언
bool check1(int[][5], vector<int>&, int);
// 주어진 크기 l의 집합을 구성하는 함수
bool func(int graph1[][5], vector<int>&arr1,
int l, int index1, bool sol1[]){
    // 선택된 집합이 독립 집합인지 확인.
    // 독립 집합이라면 sol 값을 true로 바꾸고 반환
      if (l == 0){
          if (check1(graph1, arr1, arr1.size())){
             sol1[0] = true;
             return true;
          }
      }
      else{
          // 현재 인덱스의 정점을 포함하지 않아도
          // 크기 l의 집합을 만들 수 있는 경우
          if (index1 >= l){
             vector<int> newvec(arr1.begin(), arr1.end());
             newvec.push_back(index1);
             return (func(graph1, newvec, l - 1,
             index1 - 1, sol1) or
             func(graph1, arr1, l, index1 - 1, sol1));
          }
            // 현재 인덱스의 정점을 포함하지 않으면
          // 크기 l의 집합을 만들 수 없는 경우
          else{
             arr1.push_back(index1);
             return func(graph1, arr1, l - 1,
             index1 - 1, sol1);
          }
      }
   }
   // 주어진 집합이 독립 집합인지
   // 검사하는 함수
   // arr --> 크기 l의 집합 (포함된 정점의
   // 인덱스를 저장)
   bool check1(int graph1[][5], vector<int>&arr1, int n1){
      // 집합 내 각 정점이 다른 정점과
         // 연결되어 있는지 확인
        for (int i = 0; i < n1; i++)
            for (int j = i + 1; j < n1; j++)
               if (graph1[arr1[i]][arr1[j]] == 1)
               return false;
        return true;
}
// 드라이버 코드
int main(){
    int graph1[][5] = {{1, 0, 1, 0, 0},{0, 1, 1, 0, 0},{1, 1, 1, 1, 1},{0, 0, 1, 1, 0},
      {0, 0, 1, 0, 1}};
      int l = 4;
      vector<int> arr1; // 빈 집합
      bool sol1[] = {false};
      int n1 = sizeof(graph1) /
      sizeof(graph1[0]);
      func(graph1, arr1, l, n1 - 1, sol1);
      if (sol1[0])
          cout << "Yes" << endl;
      else
          cout << "No" << endl;
      return 0;
}

실행 결과

Yes

코드 설명

func 함수는 재귀적으로 크기 l의 정점 집합을 구성합니다. 현재 인덱스의 정점을 집합에 포함하는 경우와 포함하지 않는 경우를 모두 탐색하며, 남은 정점 수만으로는 목표 크기를 채울 수 없을 때는 반드시 현재 정점을 포함하도록 하여 불필요한 탐색을 줄입니다.

check1 함수는 선택된 정점들 사이에 간선이 하나라도 존재하는지 검사합니다. 인접 행렬에서 해당 위치의 값이 1이면 두 정점이 연결된 것이므로 독립 집합이 아니며 false를 반환합니다. 모든 정점 쌍이 서로 연결되어 있지 않다면 true를 반환하여 유효한 독립 집합임을 알립니다.