A bacteria called streptosquarus comes in very peculiar shapes. The streptosquarus is flat with no perceived thickness. (It is essentially two-dimensional.) It is composed of an integer number of unit squares.

In addition, all the squares in the streptosquarus must be touching at least one other square of the bacteria along edges. 

Write a program that takes a positive integer from the user and returns the number of possible different streptosquarus shapes of that size. Notice that there is only one streptosquarus of sizes one and two, but there are two of size three, five of size four, and 12 of size five.

모든 가능한 스트렙토스쿼러스의 형태를 생성하고, 회전과 대칭에 의한 중복을 제거하여 유일한 형태의 수를 계산해야 합니다. 회전과 대칭을 확인하는 로직을 추가하여 중복을 제거하는 것이 핵심입니다.

이 알고리즘은 크기가 커질수록 매우 느려질 수 있으므로, 크기가 5를 초과하는 경우에는 실행 시간을 고려해야 합니다.

from collections import deque


def generate_streptosquarus(n):
    if n == 1:
        return 1

    # All possible moves from a square
    moves = [(0, 1), (1, 0), (0, -1), (-1, 0)]

    # Generate all possible shapes by adding a square to each exposed edge
    def generate_shapes(current_shape):
        new_shapes = set()
        for x, y in current_shape:
            for dx, dy in moves:
                new_pos = (x + dx, y + dy)
                if new_pos not in current_shape:
                    new_shape = current_shape | {new_pos}
                    new_shapes.add(frozenset(new_shape))
        return new_shapes

    # Normalize shapes by rotating and flipping to remove duplicates
    def normalize(shape):
        # Convert frozenset to a sorted list of tuples to allow rotations and flips
        shape = sorted(shape)

        def rotate(shape):
            return sorted((y, -x) for x, y in shape)

        def flip(shape):
            return sorted((-x, y) for x, y in shape)

        # Generate all unique rotations and flips of the shape
        unique_transforms = {tuple(shape)}
        for _ in range(3):  # Rotate three more times
            shape = rotate(shape)
            unique_transforms.add(tuple(shape))

        # Flip the shape and get all its rotations
        shape = flip(shape)
        unique_transforms.add(tuple(shape))
        for _ in range(3):  # Rotate three more times
            shape = rotate(shape)
            unique_transforms.add(tuple(shape))

        # Normalize to ensure all shapes start from (0, 0)
        def normalize_shape(transform):
            min_x = min(x for x, y in transform)
            min_y = min(y for x, y in transform)
            return tuple((x - min_x, y - min_y) for x, y in transform)

        normalized_shapes = set(normalize_shape(transform) for transform in unique_transforms)
        return min(normalized_shapes)  # Return the smallest normalized shape

    # Use a set to store all unique shapes
    unique_shapes = set()

    # Starting queue with a single square
    queue = deque([frozenset([(0, 0)])])
    while queue:
        shape = queue.popleft()
        if len(shape) == n:
            norm_shape = normalize(shape)
            unique_shapes.add(norm_shape)
        else:
            for new_shape in generate_shapes(shape):
                queue.append(new_shape)

    return len(unique_shapes)


# Example usage
def main():
    print("Enter a positive integer or 'q' to quit.")
    while True:
        user_input = input("Enter a integer number or 'q' to quit: ")
        if user_input.lower() == 'q':
            print("Program has ended.")
            break
        try:
            n = int(user_input)
            if n < 1:
                print("Warning: Please enter a positive integer.")
            elif n > 6:
                print("Warning: Calculations for numbers greater than 6 may be slow.")
            result = generate_streptosquarus(n)
            print(f"Number of possible shapes for a streptosquarus of size {n}: {result}")
        except ValueError:
            print("Warning: Please enter a valid integer or 'q' to quit.")


if __name__ == "__main__":
    main()



DALL-E3 가 그려준 KW IT 전산인 모임 8주년 이미지


다익스트라 알고리즘은 그래프 내의 한 정점에서 다른 모든 정점까지의 최단 경로를 찾는 알고리즘입니다. 다음은 자바스크립트로 다익스트라 알고리즘을 구현한 예시와 해당 코드의 설명입니다.

구현:

class PriorityQueue {
  constructor() {
    this.values = [];
  }

  enqueue(val, priority) {
    this.values.push({ val, priority });
    this.sort();
  }

  dequeue() {
    return this.values.shift();
  }

  sort() {
    this.values.sort((a, b) => a.priority - b.priority);
  }
}

class WeightedGraph {
  constructor() {
    this.adjacencyList = {};
  }

  addVertex(vertex) {
    if (!this.adjacencyList[vertex]) this.adjacencyList[vertex] = [];
  }

  addEdge(vertex1, vertex2, weight) {
    this.adjacencyList[vertex1].push({ node: vertex2, weight });
    this.adjacencyList[vertex2].push({ node: vertex1, weight });
  }

  Dijkstra(start, finish) {
    const nodes = new PriorityQueue();
    const distances = {};
    const previous = {};
    let path = [];
    let smallest;

    for (let vertex in this.adjacencyList) {
      if (vertex === start) {
        distances[vertex] = 0;
        nodes.enqueue(vertex, 0);
      } else {
        distances[vertex] = Infinity;
        nodes.enqueue(vertex, Infinity);
      }
      previous[vertex] = null;
    }

    while (nodes.values.length) {
      smallest = nodes.dequeue().val;
      if (smallest === finish) {
        while (previous[smallest]) {
          path.push(smallest);
          smallest = previous[smallest];
        }
        break;
      }

      if (smallest || distances[smallest] !== Infinity) {
        for (let neighbor in this.adjacencyList[smallest]) {
          let nextNode = this.adjacencyList[smallest][neighbor];
          let candidate = distances[smallest] + nextNode.weight;
          let nextNeighbor = nextNode.node;

          if (candidate < distances[nextNeighbor]) {
            distances[nextNeighbor] = candidate;
            previous[nextNeighbor] = smallest;
            nodes.enqueue(nextNeighbor, candidate);
          }
        }
      }
    }
    return path.concat(smallest).reverse();
  }
}

설명:

  1. PriorityQueue: 우선순위 큐를 구현한 클래스입니다. 이 큐는 다익스트라 알고리즘에서 가장 짧은 거리의 정점을 빠르게 찾기 위해 사용됩니다.
  2. WeightedGraph: 가중치가 있는 그래프를 나타내는 클래스입니다.
  3. addVertex: 그래프에 정점을 추가하는 메서드입니다.
  4. addEdge: 그래프에 간선과 그 간선의 가중치를 추가하는 메서드입니다.
  5. Dijkstra: 다익스트라 알고리즘을 구현한 메서드입니다. 시작 정점과 종료 정점을 인수로 받아서 시작 정점에서 종료 정점까지의 최단 경로를 배열로 반환합니다.

이 코드는 간선의 가중치가 양수일 때만 작동합니다. 만약 음수 가중치의 간선이 있다면, 다른 알고리즘을 사용해야 합니다.

포인터는 C와 C++ 언어의 핵심 개념 중 하나입니다. 이를 이해하는 것은 두 언어를 효과적으로 사용하기 위해 필수적입니다.

포인터란?

포인터는 메모리 주소를 저장하는 변수입니다. 다시 말해, 포인터는 어떤 데이터의 위치(메모리 주소)를 가리키는 변수입니다.

기본 사용법:

  1. 선언:
    int *p; // 정수형 포인터 char *ch; // 문자형 포인터
  2. 주소 연산자 &: 변수의 메모리 주소를 가져오는 데 사용됩니다.
    int x = 10; p = &x; // p는 x의 주소를 가리킵니다.
  3. 역참조 연산자 (*): 포인터가 가리키는 주소의 값을 가져옵니다.
    int value = *p; // value는 10이 됩니다. p가 x의 주소를 가리키기 때문입니다.

포인터의 이점:

  1. 동적 메모리 할당: malloc(), calloc(), new 등의 함수나 연산자를 사용하여 실행 시간에 메모리를 할당할 수 있습니다.
  2. 배열과 문자열: 포인터를 사용하여 배열의 요소에 접근하거나 문자열을 관리할 수 있습니다.
  3. 함수와 구조체로의 참조 전달: 값 전달 대신 참조 전달을 사용하여 효율적으로 데이터를 전달하거나 변경할 수 있습니다.
  4. 데이터 구조: 링크드 리스트, 트리, 그래프와 같은 고급 데이터 구조를 구현할 때 필수적입니다.

주의사항:

  1. 와일드 포인터 (Dangling Pointer): 초기화되지 않은 포인터는 예측할 수 없는 메모리 주소를 가리키게 됩니다. 이러한 포인터를 역참조하면 프로그램에 오류가 발생할 수 있습니다.
  2. 메모리 누수: 동적으로 할당된 메모리를 적절히 해제하지 않으면 메모리 누수가 발생할 수 있습니다. C에서는 free(), C++에서는 delete를 사용하여 메모리를 해제해야 합니다.
  3. 포인터 연산: 포인터에 정수를 더하거나 빼면 해당 타입의 크기만큼 주소가 변경됩니다. 이를 활용하여 배열의 요소에 접근할 수 있지만, 주의하지 않으면 포인터가 유효한 메모리 범위를 벗어날 수 있습니다.

C++에서의 참고사항:

C++에서는 포인터 외에도 참조(reference)라는 개념이 추가로 있습니다. 참조는 원래의 변수를 '가리키는' 다른 이름이라고 생각할 수 있으며, 포인터보다 사용하기 쉽고 안전합니다.

결론:

포인터는 강력하면서도 복잡한 개념입니다. 올바르게 사용하면 프로그램의 효율성과 유연성을 크게 향상시킬 수 있지만, 주의하지 않으면 오류의 원인이 될 수 있습니다. 따라서 포인터를 사용할 때는 항상 주의를 기울여야 합니다.

std::vector는 C++ 표준 템플릿 라이브러리(STL)의 일부로서, 동적 배열과 유사한 구조를 가진 컨테이너입니다.

std::vector의 주요 특징:

  1. 동적 크기: 백터는 크기가 동적으로 변경될 수 있습니다. 즉, 런타임에 항목을 추가하거나 제거할 수 있습니다.
  2. 연속 메모리: 백터는 내부적으로 연속된 메모리 공간에 데이터를 저장합니다. 따라서 배열처럼 인덱스를 사용하여 빠르게 접근할 수 있습니다.
  3. 자동 메모리 관리: 백터는 내부적으로 메모리를 자동으로 할당하고 해제합니다.

std::vector의 사용 예:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers;

    // 값을 추가합니다.
    numbers.push_back(1);
    numbers.push_back(2);
    numbers.push_back(3);

    // 인덱스를 사용하여 값에 접근합니다.
    std::cout << numbers[1] << std::endl;  // 출력: 2

    // 크기와 용량을 조회합니다.
    std::cout << "Size: " << numbers.size() << std::endl;  // 출력: 3
    std::cout << "Capacity: " << numbers.capacity() << std::endl;

    // 반복자를 사용하여 백터의 요소를 반복합니다.
    for(int num : numbers) {
        std::cout << num << " ";
    } // 출력: 1 2 3

    return 0;
}

이 외에도 std::vector는 여러 메서드와 기능을 제공합니다. 예를 들면 insert, erase, resize, reserve 등이 있습니다. C++의 std::vector를 효과적으로 사용하려면 해당 메서드와 기능들을 숙지하는 것이 중요합니다.

Cimetech Bluetooth Numeric Keypad, 22-Keys Wireless Number Pad K304 Manual PDF
https://drive.google.com/file/d/1bTF3H9KNUHBFiseui2qHGQ92Vx_uVYGG/view?usp=drive_link


Amazon Link
https://www.amazon.ca/cimetech-Multi-Function-Accounting-Extensions-Compatible/dp/B0BG8BPN9C?ref_=ast_sto_dp&th=1


C++에서의 참조는 변수나 객체의 별칭을 제공하는 방법입니다. 참조를 사용하면 변수나 객체에 대한 간접적인 접근을 할 수 있습니다. 여기서 주요 포인트와 예제를 통해 C++의 참조 개념을 설명하겠습니다.

  1. 참조의 선언: 참조는 & 기호를 사용하여 선언됩니다. 예를 들어, int 타입의 변수에 대한 참조는 다음과 같이 선언할 수 있습니다.

    int num = 10;
    int &ref = num;

  2. 참조의 특징:
    • 참조는 선언과 동시에 초기화되어야 합니다.
    • 한번 초기화된 참조는 다른 변수나 객체를 참조하도록 변경할 수 없습니다.
    • 참조는 NULL 값을 가질 수 없습니다.
  3. 참조와 포인터의 차이:
    • 포인터는 메모리 주소를 저장하는 반면, 참조는 별칭으로 작동하며 메모리 주소를 직접 저장하지 않습니다.
    • 포인터는 *와 & 연산자를 사용하여 역참조하고 주소를 얻는 반면, 참조는 추가적인 연산자 없이도 원래의 변수나 객체에 접근할 수 있습니다.
  4. 참조의 활용:
    • 함수의 인자로 사용될 때, 값을 복사하는 것이 아닌 원래의 변수나 객체에 대한 접근을 제공하므로 효율적입니다.
    • 함수에서 여러 값을 반환할 필요가 있을 때 사용됩니다.
  5. 예제:위의 예제에서 swap 함수는 참조를 인자로 받아 원래의 변수의 값을 직접 변경합니다.

    void swap(int &x, int &y)
    {
        int temp = x;
        x = y;
        y = temp;
    }

    int main()
    {
        int a = 5, b = 10;
        swap(a, b);
        cout << "a: " << a << ", b: " << b; // a: 10, b: 5
        return 0;
    }

       이러한 참조의 개념은 C++에서 매우 중요하며, 효율적인 프로그래밍을 위해 잘 알아두어야 합니다.


Qualcomm은 새로운 Snapdragon Elite X 칩을 발표하여 노트북 시장에서 Intel, AMD 및 Apple과의 경쟁력을 강화하려 한다. 이 칩은 2024년부터 노트북에서 사용 가능하며 인공 지능 작업을 더 잘 처리할 수 있도록 재설계되었다. Qualcomm은 X Elite가 일부 작업에서 Apple의 M2 Max 칩보다 빠르며 Apple 및 Intel PC 칩보다 에너지 효율이 뛰어나다고 주장했다.

 

이 새로운 칩은 4nm 프로세스 기술을 기반으로 하며, 3.8GHz의 12개의 고성능 코어와 최대 4.3GHz까지의 듀얼 코어 부스트를 제공한다. 또한 Qualcomm은 CPU 메모리 성능을 향상시켰다고 밝혔다. Qualcomm의 이러한 발표는 PC 칩 경쟁에서 Qualcomm, Apple, Intel 간의 레이스를 가열시키고 있으며, Qualcomm은 Snapdragon X Elite를 "PC용으로 만든 가장 강력한 컴퓨팅 프로세서"로 부르며, 최고 수준의 CPU 성능, 선도적인 기기 내 AI 추론 및 매우 효율적인 전문 처리 기능을 제공한다고 주장했다.

 

이러한 발표와 새로운 칩 기술은 Qualcomm이 노트북 시장에서 Intel, AMD 및 Apple과의 경쟁에서 어떻게 위치할지에 대한 통찰력을 제공하며, 노트북 사용자에게 더 나은 성능과 효율성을 제공할 가능성을 보여준다.

 

특히 소프트웨어 개발자 입장에서 애플 실리콘 칩을 내장한 맥이 최신 인텔 칩을 내장한 윈도 PC 보다 컴파일이나 트랜스파일링 속도가 빠르지도 않았으며 가격이 비싸 가성비가 떨어지는 선택이었다. 장점은 어떠한 작업을 해도 하루 종일 버티는 베터리, 빠른 비디오 처리와 압축정도 였는데 이것은 개발자 입장에선 꼭 필요한 장점은 아니다.

+ Recent posts