반응형

데바데 자동 구매는 어떤 방법일까? 해서 심심해서 비슷하게 구현해보았다.

 

데드바이 데이라이트를 플레이하던 중  게임에는 아래와 같이

아이템을 구매하는 시스템이 존재한다.

 

해당 페이지의 중앙 버튼은 아이템을 자동으로 구입해 주는 시스템인데 아무 생각 없이 보고 있다 문득 

해당 페이지에서 사용하는 알고리즘이 무엇인지 궁금해졌다

 

처음 문득 생각했을 때는 다익스트라 또는 최소 스패닝트리를 사용했을 거 같았다.

 

당연하게도 전체적으로 가장 저렴한 루트를 제공할 것이라고 생각했기 때문이다.

 

알고리즘을 분석하기위해 자동 구매를 하며 영상녹화 한 뒤

 

분석하던 도중 이상한 순서로 구매하는 것을 확인하고 의문이 들어서  찾던 중 아래와 같은 사실을 확인해 버렸다.

 

 

 

 깊이가 가까운 노드에서 가격이 저렴한 순서대로 샀다는 것이다.

 

그렇다는 건

 

가깝고 싼 순서부터 우선순위  더 싸더라도 한 칸이라도 멀리 있으면 비싼 걸 구매한다.

 

 

무서운 진실(최대한 싸게 구매하지 않는다는) 사실을  알아버렸지만 좌절하고 있을 수는 없다.

 

계속 분석해보자

 

 

배치는 어떤 식일까?

그렇다면 배치는 어떤 식으로 만들어지는지 자세히 보기 위해  좀 더 많은 배치가 있는 화면을 들고 와보았다.

자~세하게 본다면 미리 배치가 일정 정해져 있는 것을 볼 수 있다.

RootNode

Depth 1  노드수 6개

Depth 2  노드수 12개

Depth 3  노드수 12개

 

깊이에 비례해서 노드수가 커지지는 않는 것 같다.

 

간선은  

RootNode  = Depth 1 간선 6개

Depth 1      = Root Node + 같은 Depth 간선 최대 2개  + Depth +1 간선 2개

Depth 2      = Depth 1 간선 최대 2개 + 같은 Depth 간선 최대 2개  + Depth +1 간선 2개

Depth 3      = Depth 2 간선 최대 2개 + 같은 Depth 간선 최대 2개 

 

정도로 보인다.

 

 

 

해당 시스템을 그대로 만든다면 
미리 노드들과 위치 연결된 간선을 만들어둔 뒤

 

root 노드에서 BFS 나 DFS로 만 들것 같다.

 

하지만 아이템 등장 확률이나 간선 노드 생성 수식을 모르니

임시로 만들어보았다.

 

 

 

3개의 깊이로 2번 3번에서는 왼쪽과 아래 간선을 랜덤 하게 연결하는 식으로 만들었다.

 

깊이당 노드도 랜덤이기에

 

 

 

 

큰 기획 없이 랜덤 하게 스폰하게 만든 간단한 그래프기에   

 

더 외부의 그래프의 노드가  적다면 

간선끼리 겹치거나 이미지 뒤로 겹치는 경우도 존재한다.

 

생성 후 가까운 노드에 연결하는 방식도 생각해 보았지만 

우선 대부분은 큰 문제가 없기 때문에 이후 수정하는 것으로 하자.

 

아래는 잘 나온 그래프.

 

 

 

간선이 겹치는 경우

 

 

 

이제 데바데의 형식으로  먹는 것을 계산해 보자

 

 

 

 

 

우선 아이템만 존재할 때 먹는 걸 만들었다.

https://youtu.be/SVtNEP8hgnE

 

https://youtu.be/WlBpLT75-48

 

 

 

https://youtu.be/50XT6vks62Q

 

 

 

 

 

 

더보기
using NUnit.Framework;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System;
using Unity.VisualScripting;
using UnityEngine.UI;
using System.Net;
using System.Collections;

public class BloodwebSystem : MonoBehaviour
{

    private PriorityQueue<(int, ItemScriptableObject), (int, int)> queue;
    private ItemScriptableObject RootItems;
    private Dictionary<int, List<LineRenderer>> lineRenderers = new Dictionary<int, List<LineRenderer>>();
    private Dictionary<(int, int), LineRenderer> EdgeDicrionaty = new Dictionary<(int, int), LineRenderer>();

    private Queue<int> Deadny_Auto = new Queue<int>();
    private List<bool> Deadny_ison;
    //아이템리스트
    public List<ItemScriptableObject> PabItems;
    private List<ItemScriptableObject> ItemList = new List<ItemScriptableObject>();
    // ui 생성위치
    public GameObject MakeBloodwebPoint;
    public GameObject MakeBloodwebLinePoint;
    //깊이당 생성 저장
    public List<List<ItemScriptableObject>> BloodwebDepth;

    public GameObject BloodObjectPrefab;


    public GameObject BloodObjectLinePrefab;


    [SerializeField, UnityEngine.Range(1, 30)]
    public int MaxPoint = 25;
    public int MaxPath = 25;


    [SerializeField, UnityEngine.Range(1, 100)]
    public int CircleRadius = 25;


    private List<(int, int)> DijkstraInts = new List<(int, int)>(), DBDSerchInts = new List<(int, int)>(), SmallSerchInts = new List<(int, int)>();

    // 데이터 시트 구현
    void Start()
    {

        Init();
        //queue = new PriorityQueue<ItemScriptableObject, (int, int)>();
        //queue.Enqueue(new ItemScriptableObject { price = 3 }, (0, 1000));
        //queue.Enqueue(new ItemScriptableObject { price = 1 }, (-1, 2000));
        //queue.Enqueue(new ItemScriptableObject { price = 2 }, (-1, 3000));
        //queue.Enqueue(new ItemScriptableObject { price = 4 }, (1, -2000));
        //queue.Enqueue(new ItemScriptableObject { price = 5 }, (2, 0));

        //while (queue.Count > 0)
        //{
        //    Debug.Log(queue.Dequeue().price);
        //}

    }
    //가격순 정렬
    int compareItem(ItemScriptableObject a, ItemScriptableObject b)
    {
        return a.price < b.price ? -1 : 1;
    }

    private void Init()
    {
        //3개의 뎁스
        queue = new PriorityQueue<(int, ItemScriptableObject), (int, int)>();
        BloodwebDepth = new List<List<ItemScriptableObject>>(3);
        RootItems = new ItemScriptableObject { price = -1, edge = new List<ItemScriptableObject>() };
        //PabItems 갑어치에 따른 정렬
        PabItems.Sort(compareItem);


        int min = 8;
        int max = 12;

        int number = 0;

        for (int i = 0; i < 3; ++i)
        {
            BloodwebDepth.Add(new List<ItemScriptableObject>());

            float randomValue = UnityEngine.Random.Range(0f, 1f);
            float bias = 2f + i;
            int selectedValue = Mathf.FloorToInt(min + Mathf.Pow(randomValue, bias) * (max - min + 1));

            if (i == 0)
            {
                selectedValue = 6;
            }
            for (int j = 0; j < selectedValue; ++j)
            {

                int R_Number = UnityEngine.Random.Range(0, PabItems.Count);
                //가치에 따른 낮은 확율 생성 필요
                ItemScriptableObject tempI = new ItemScriptableObject
                {
                    numbering = number,
                    price = PabItems[R_Number].price,
                    Sprite = PabItems[R_Number].Sprite,
                    depth = i,
                    edge = new List<ItemScriptableObject>()
                };
                lineRenderers.Add(number, new List<LineRenderer>());

                number++;
                BloodwebDepth[i].Add(tempI);
                ItemList.Add(tempI);



            }
        }

        (int, int)[] edges = { (-1, 0), (0, -1) };
        DrawBloodWeb();

        for (int i = 0; i < BloodwebDepth.Count; ++i)
        {
            for (int j = 0; j < BloodwebDepth[i].Count; ++j)
            {
                if (i == 0)
                {
                    RootItems.edge.Add(BloodwebDepth[i][j]);


                    var d = DrawLine(MakeBloodwebLinePoint.transform.position, BloodwebDepth[i][j].g.transform.position);
                    EdgeDicrionaty.Add((-1, j), d);

                    //옆라인 연결 있든없든 상관없음 
                }
                else
                {
                    int numToSelect = UnityEngine.Random.Range(1, edges.Length + 1);
                    bool[] selectedFlags = new bool[edges.Length];

                    while (BloodwebDepth[i][j].edge.Count < numToSelect)
                    {
                        int randomIndex = UnityEngine.Random.Range(0, edges.Length);

                        // 이미 선택된 항목인지 확인
                        if (!selectedFlags[randomIndex])
                        {
                            int TDepth = i + (edges[randomIndex].Item1);
                            int whith = j + edges[randomIndex].Item2;


                            if (whith < 0) whith = BloodwebDepth[i].Count - 1;
                            if (BloodwebDepth[TDepth].Count - 1 < whith) whith = (BloodwebDepth[TDepth].Count - 1) % whith;
                            if (BloodwebDepth[TDepth][whith]) selectedFlags[randomIndex] = true;

                            BloodwebDepth[i][j].edge.Add(BloodwebDepth[TDepth][(whith)]);
                            BloodwebDepth[TDepth][whith].edge.Add(BloodwebDepth[i][j]);

                            var d = DrawLine(BloodwebDepth[i][j].g.transform.position, BloodwebDepth[TDepth][whith].g.transform.position);
                            lineRenderers[BloodwebDepth[i][j].numbering].Add(d);
                            lineRenderers[BloodwebDepth[TDepth][whith].numbering].Add(d);
                            EdgeDicrionaty.Add((BloodwebDepth[i][j].numbering, BloodwebDepth[TDepth][whith].numbering), d);
                            EdgeDicrionaty.Add((BloodwebDepth[TDepth][whith].numbering, BloodwebDepth[i][j].numbering), d);
                        }
                    }
                }
            }
        }

        Debug.Log("end");
        //미리 계산하기
        Deadny_Auto = Deadny_AutoChoiceAll();
        Deadny_AutoDraw(Deadny_Auto);

        //DBDSerchInts = DbdDirections();
        //DijkstraInts = DijkstraAll();
        SmallSerchInts = SmallerDirections();

        //StartCoroutine(drawingColor(DBDSerchInts));
        //StartCoroutine(drawingColor(DijkstraInts));
        StartCoroutine(drawingColor(SmallSerchInts));

    }


    private LineRenderer DrawLine(Vector3 x, Vector3 y)
    {

        GameObject lineObject = Instantiate(BloodObjectLinePrefab, MakeBloodwebLinePoint.transform);
        LineRenderer lr = lineObject.GetComponent<LineRenderer>();
        lr.SetPosition(0, x);
        lr.SetPosition(1, y);
        lr.sortingOrder = -1;
        return lr;
    }
    private void DrawBloodWeb()
    {
        Vector3 UITransformPosition = MakeBloodwebPoint.transform.position;

        for (int i = 0; i < BloodwebDepth.Count; i++)
        {

            float CircleRate = (CircleRadius * 0.1f) * (i + 1);
            int count = BloodwebDepth[i].Count;
            for (int j = 0; j < BloodwebDepth[i].Count; j++)
            {
                float theta = (2 * MathF.PI / count) * j;
                var data = BloodwebDepth[i][j];
                data.position.x = UITransformPosition.x + CircleRate * MathF.Cos(theta);
                data.position.y = UITransformPosition.y + CircleRate * MathF.Sin(theta);
                Vector3 ObjectTransformPosition = new Vector3(data.position.x, data.position.y, 0);


                GameObject G = Instantiate(BloodObjectPrefab, MakeBloodwebPoint.transform);
                G.transform.position = ObjectTransformPosition;
                G.GetComponent<Image>().sprite = BloodwebDepth[i][j].Sprite;
                BloodwebDepth[i][j].g = G;

            }
        }
    }
    public Queue<int> Deadny_AutoChoiceAll()
    {
        Deadny_ison = new List<bool>(ItemList.Count + 1);
        for (int i = 0; i < ItemList.Count + 1; ++i)
        {
            Deadny_ison.Add(false);
        }
        Queue<int> temp = new Queue<int>();
        queue.Enqueue((0, RootItems), (0, 0));
        while (queue.Count > 0)
        {
            (int, ItemScriptableObject) data = queue.Dequeue();
            int num = data.Item1;
            if (data.Item2.numbering != -1)
            {
                temp.Enqueue(data.Item2.numbering);
                Deadny_ison[data.Item2.numbering] = true;
            }
            foreach (var edge in data.Item2.edge)
            {
                if (Deadny_ison[edge.numbering] == false)
                {
                    queue.Enqueue((num + edge.price, edge), (edge.depth, num + edge.price));
                }
            }
        }
        return temp;
    }
    public void Deadny_AutoDraw(Queue<int> deadny_Auto)
    {
        while (deadny_Auto.Count > 0)
        {
            int num = deadny_Auto.Dequeue();
            ItemList[num].g.GetComponent<Button>().image.color = new Color(144, 55, 55);
            Debug.Log(ItemList[num].g.GetComponent<Image>().sprite);

        }
    }

    public void NodeNtoChangeColor(int BaseNodeNumber, int ChangeNodeNumber, Color EdgeColor, Color ItemColor)
    {
        EdgeDicrionaty[(BaseNodeNumber, ChangeNodeNumber)].startColor = EdgeColor;
        EdgeDicrionaty[(BaseNodeNumber, ChangeNodeNumber)].endColor = EdgeColor;
        ItemList[ChangeNodeNumber].g.GetComponent<Button>().image.color = (ItemColor);
    }


    private IEnumerator drawingColor(List<(int,int)>Ints)
    {
        foreach ((int, int) d in Ints)
        {
            Debug.Log(d);
            NodeNtoChangeColor(d.Item1, d.Item2, Color.green, Color.black);
            yield return new WaitForSeconds(1f);

        }
    }



    //이후 탐색클래스 분리
    public List<(int, int)> DijkstraAll()
    {
        List<(int, int)> list = new List<(int, int)>();
        PriorityQueue<(ItemScriptableObject, int, int), (int, int)> dijksqueue = new PriorityQueue<(ItemScriptableObject, int, int), (int, int)>();
        dijksqueue.Enqueue((RootItems, -1, 0), (0, 0));
        List<bool> complete = new List<bool>();
        foreach (ItemScriptableObject item in ItemList)
        {
            complete.Add(false);
        }

        while (dijksqueue.Count != 0)
        {

            var data = dijksqueue.Dequeue();
            Debug.Log(data.Item1.numbering);

            if (data.Item1.numbering != -1)
            {
                if (complete[data.Item1.numbering] == true) continue;
                list.Add((data.Item2, data.Item1.numbering));
                complete[data.Item1.numbering] = true;

            }
            foreach (var edge in data.Item1.edge)
            {
                int dijkcost = edge.price + data.Item3;
                if (complete[edge.numbering] == true) continue;

                dijksqueue.Enqueue((edge, data.Item1.numbering, dijkcost), (dijkcost, 0));
            }
        }
        return list;
    }

    public List<(int, int)> SmallerDirections()
    {
        List<(int, int)> list = new List<(int, int)>();
        PriorityQueue<(ItemScriptableObject, int, int), (int, int)> dijksqueue = new PriorityQueue<(ItemScriptableObject, int, int), (int, int)>();
        dijksqueue.Enqueue((RootItems, -1, 0), (0, 0));
        List<bool> complete = new List<bool>();
        foreach (ItemScriptableObject item in ItemList)
        {
            complete.Add(false);
        }

        while (dijksqueue.Count != 0)
        {

            var data = dijksqueue.Dequeue();
            Debug.Log(data.Item1.numbering);

            if (data.Item1.numbering != -1)
            {
                if (complete[data.Item1.numbering] == true) continue;
                list.Add((data.Item2, data.Item1.numbering));
                complete[data.Item1.numbering] = true;

            }
            foreach (var edge in data.Item1.edge)
            {
                int dijkcost = edge.price + data.Item3;
                if (complete[edge.numbering] == true) continue;

                dijksqueue.Enqueue((edge, data.Item1.numbering, dijkcost), (edge.price, 0));
            }
        }
        return list;
    }
    public List<(int, int)> DbdDirections()
    {
        List<(int, int)> list = new List<(int, int)>();
        PriorityQueue<(ItemScriptableObject, int, int), (int, int)> dijksqueue = new PriorityQueue<(ItemScriptableObject, int, int), (int, int)>();
        dijksqueue.Enqueue((RootItems, -1, 0), (0, 0));
        List<bool> complete = new List<bool>();
        foreach (ItemScriptableObject item in ItemList)
        {
            complete.Add(false);
        }

        while (dijksqueue.Count != 0)
        {

            var data = dijksqueue.Dequeue();
            Debug.Log(data.Item1.depth);

            if (data.Item1.numbering != -1)
            {
                if (complete[data.Item1.numbering] == true) continue;
                list.Add((data.Item2, data.Item1.numbering));
                complete[data.Item1.numbering] = true;

            }
            foreach (var edge in data.Item1.edge)
            {
                int dijkcost = edge.price + data.Item3;
                if (complete[edge.numbering] == true) continue;

                dijksqueue.Enqueue((edge, data.Item1.numbering, dijkcost), (edge.depth, edge.price));
            }
        }
        return list;
    }
}

 

이후  추가 예정.

 

간선 겹침 해결

이후 아이템 노드 잠김 
잠기는 노드에 따른 최적치 계산

'엔진 > 유니티' 카테고리의 다른 글

unity shortcuts  (0) 2024.09.03
유니티 데칼 (decal)  (0) 2024.04.16
구글 gemini api 유니티에서 사용하기  (0) 2023.12.21
Unity Spline 기능 추가!  (1) 2023.06.01
ChatGPT-Unity에서-사용하기  (5) 2023.03.22
반응형

20250417 

 

AI 쌀먹 하는 여인들

 

캐릭터가 제대로 뽑아지는지 테스트 해보자  이펙트역시 뽑아볼것

 

우선 할것 stablediffusion web ui 세팅

 

파이썬0250417 

 

캐릭터가 제대로 뽑아지는지 테스트 해보자 이펙트역시 뽑아볼것

 

 

영상이 설명을 잘해준다 영상을 보고 하는게 빠르겠지만 그냥 서술해본다.

참고 할것 들 

 

 

 

우선 할것 stablediffusion web ui 세팅

 

 

 

파이썬 버전 3.10.11 설치

 

가상환경 시스템 venv

venv란?  파이썬에서 제공하는 라이브러리 가상공간 이라고 생각하면 된다.

아나콘다 처럼 가상의 공간을 할당하여 

파이썬 프로젝트 끼리 필요한 라이브러리가 충돌나지않게 관리해주며

한번에 관리하기에 설정하기도 편리하다

 

만약 파일위치를 바꿔서 실행이 안된다거나 파일위치를 변경해줘야한다면

venv 파일내의 라이브러리 위치 설정을 다시설정해줘야

 

 

 

프로젝트 파일위치 C:\python\2dCreateAnime

 

 

1.

가상환경 만들기 python -m venv 이름(venv)

 

 

2.

접속 (이름)venv\Scripts\activate

# 가상 환경을 비활성화하는 코드 deactivate

 

가상환경 세팅 txt로 뽑는법

pip freeze > requirements.txt

 

다운로드법

pip install -r requirements.txt

 

 

 

 

3. 

아래 깃허브를 설치 해준다

🔗 Forge GitHub
👉 https://github.com/lllyasviel/stable-diffusion-webui-forge

 

GitHub - lllyasviel/stable-diffusion-webui-forge

Contribute to lllyasviel/stable-diffusion-webui-forge development by creating an account on GitHub.

github.com

 

git clone https://github.com/lllyasviel/stable-diffusion-webui-forge
cd stable-diffusion-webui-forge
python launch.py --xformers

 

아래 파일을 통해 라이브러리를 설치해준다.

 

파일위치로 이동한뒤

pip install -r requirements_versions.txt

실행하여 라이브러리 설치

 

 

 

 

 

 

 

stable-diffusion의 모델을 설치해준다.

https://huggingface.co/Comfy-Org/stable-diffusion-v1-5-archive/tree/main 

 

Comfy-Org/stable-diffusion-v1-5-archive at main

 

huggingface.co

C:\python\2dCreateAnime\stable-diffusion-webui-forge\models\Stable-diffusion\ 위치에 다운로드 후 다시실행

 

 

 

시작시 아래 화면을 볼수있다.

 

 

local url이 활성화 되어서 http://127.0.0.1:7860 (로컬호스트)

로 열린다.

 

 

 

 

 

 

 

 

 

이제 우리가 잘아는 화면이 나온다.

 

 

 

 

 


forge의 문제 때문에 특정 모델 로드 실패로 인해  sampling method 의 몇가지가 실행 하지못했다.

버전 변경을 하다가 에러가 난뒤 꼬인듯하여 재설치 하였다.

 

더보기

가정한 경로 정보

  • Web UI 폴더 위치: C:\python\2dCreateAnime\stable-diffusion-webui-forge
  • 가상환경 이름: venv
  • 실행할 스크립트: launch.py

▶ start.bat 내용

@echo off
cd /d C:\python\2dCreateAnime\stable-diffusion-webui-forge
call venv\Scripts\activate
python launch.py --xformers
pause

 

 

# 새로 클론
cd C:\python\2dCreateAnime
git clone https://github.com/lllyasviel/stable-diffusion-webui-forge.git

 

# venv 새로 생성
python -m venv venv
venv\Scripts\activate

 

 

 

 

#venv 관련 항목 설치
cd stable-diffusion-webui-forge
pip install -r requirements.txt

 

cuda pytorch가 gpu와 호환문제

RuntimeError: Your device does not support the current version of Torch/CUDA!

pip install torch==2.1.2 torchvision==0.16.2 --index-url https://download.pytorch.org/whl/cu121

 

 

 

해당에러 발견

(xformers 의 호환성 에러)

 

해결을 위해 재설치

 

pip uninstall xformers -y

pip install torch==2.1.2 torchvision==0.16.2 --index-url https://download.pytorch.org/whl/cu121

pip install xformers==0.0.23.post1


이제 전부 완료되어서 잘나온다.

 

 

 

https://civitai.com/models/165876/2d-pixel-toolkit-2d

 

2D Pixel Toolkit (2D像素工具包) - Sprites_64 | Stable Diffusion LoRA | Civitai

QQ交流群753289747,群内会不时发布内测模型 我的游戏已上线Steam商店页面,求求各位大佬加个愿望单~↓↓↓↓↓ My game has been launched on Steam! Wishlist it now if you're interested! ❤️↓↓↓↓↓ Stea...

civitai.com

 

 

해당 모델을  다운받아 로라 파일에 저장 하면

C:\python\2dCreateAnime\stable-diffusion-webui-forge\models\Lora

아래 이미지처럼   Lora에 pixel sprites 항목이 추가된다.

 

해당 항목을 누르면  prompt에  <lora:pixel sprites:1> 가 추가되면서 설정을 추가할수있다.

또한 해당 설정을 더 잘사용하기위해 추천모델들이 존재한다.

 

https://civitai.com/models/23900/anylora-checkpoint?modelVersionId=95489

 

AnyLoRA - Checkpoint - bakedVae (blessed) fp16 NOT-PRUNED | Stable Diffusion Checkpoint | Civitai

AnyLoRA Add a ❤️ to receive future updates. Do you like what I do? Consider supporting me on Patreon 🅿️ or feel free to buy me a coffee ☕ For LCM rea...

civitai.com

 

 

 

 

 

C:\python\2dCreateAnime\stable-diffusion-webui-forge\models\Stable-diffusion 에추가하면 

위의 Chekpoint 에 새로운 항목을 추가할수 있다.

 

 

 

 

그리고는 프롬프트와 설정들을 만져주면 위와같은 깔끔한 도트를 얻을수있다.

2d의 포즈를 얻기위해서는

ControlNet Integrated 설정이 필요한데 해당설정은 다음글에서

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형

 

https://www.acmicpc.net/problem/3197

 

 

 

 


 

 

 

 

 

위 이미지처럼 

X = 얼음

.   = 호수

L  =  백조

 

하루마다 호수에 맞닿아 있는 얼음이 녹는다.

백조는 며칠뒤에 서로 만날 수 있을지 구하는 문제이다.

 

 

 


 

 

 

 

여기 주소에서 데이터를 받아볼수있다.

https://hsin.hr/2005/ 

 

 

 

 

 

 

 

 


 

 

 

문제 풀이에 사용한 알고리즘은 

BFS , UnionFind  두개다

 

 

문제는 아래 두가지 라고 생각했다.

1.얼음을 녹일 방법

2.백조가 만날수 있는지 확인할수 있는 방법

 

 

 

해결방식 

 

 

 

1.얼음의 외각을 녹일때 다음 녹을 얼음을 지정해 큐에 넣어준다.

2.얼음마다 지역을 설정해둔뒤 다른지역과 합쳐질때 서로 합쳐준다.

 

 

 

 


 

 

 

코드

 

더보기

 

#include<iostream>
#include <queue>
using namespace std;
vector<pair< int, int>> Swans;
queue<pair<int, int>> X_queue, TempQueue, * PointerQueue, * TempPointerQueue;
const static vector < vector<int>> Mover{ {1,0},{0,1},{-1,0},{0,-1} };
const static vector < vector<int>> InputMover{ {0,-1},{-1,0} };
vector<int> lakeList;

int UnionFInd(int Num) {
	if (lakeList[Num] == Num)
		return Num;
	return lakeList[Num] = UnionFInd(lakeList[Num]);
}

void Union(int Left, int Right) {
	int LNum = UnionFInd(Left);
	int RNum = UnionFInd(Right);
	if (LNum == RNum)return;
	if (LNum > RNum) {
		lakeList[LNum] = RNum;
	}
	else {
		lakeList[RNum] = LNum;
	}
}
enum Tile
{
	X = -88,
	x = -120,
	L = -76,
	dot = -46
};
void SwanLake() {
	int R, C;
	cin >> R >> C;
	vector<vector<int>> lake(R, vector<int>(C));
	vector< int> L_Point(2);
	int numb = 1;
	lakeList.push_back(0);
	for (int i = 0; i < R; ++i) {
		for (int j = 0; j < C; ++j) {
			char chardata;
			cin >> chardata;
			lake[i][j] = -(int)chardata;
			if (chardata == 'L') Swans.push_back({ i,j });
			int after = -1, before = -1;

			for (auto M : InputMover) {
				if (0 > i + M[0] || 0 > j + M[1] || R <= i + M[0] || C <= j + M[1])continue;
				if ((lake[i][j] == Tile::dot || lake[i][j] == Tile::L) && lake[i + M[0]][j + M[1]] == Tile::X) {
					X_queue.push({ i + M[0],j + M[1] });
					lake[i + M[0]][j + M[1]] = Tile::x;
				}
				if (lake[i][j] == Tile::X && lake[i + M[0]][j + M[1]] > 0) {
					X_queue.push({ i,j });
					lake[i][j] = Tile::x;
				}

				if ((lake[i][j] == Tile::dot || lake[i][j] == Tile::L) && lake[i + M[0]][j + M[1]] > 0) {
					if (after == -1) {
						after = lake[i + M[0]][j + M[1]];
					}
					else {
						before = lake[i + M[0]][j + M[1]];
					}

				}
			}
			if ((lake[i][j] == Tile::dot || lake[i][j] == Tile::L)) {
				if (after == -1) {
					lake[i][j] = numb;
					lakeList.push_back(numb++);

				}
				else if (before == -1) {
					lake[i][j] = after;
				}
				else {
					Union(after, before);
					lake[i][j] = UnionFInd(after);
				}
			}


		}
	}

	for (int i = 0; i < 2; ++i) {
		L_Point[i] = (lake[Swans[i].first][Swans[i].second]);
	}
	int day = 0;
	if (UnionFInd(L_Point[0]) == UnionFInd(L_Point[1])) {
		cout << day;
		return;
	}


	do {
		day++;
		PointerQueue = &((X_queue.empty()) ? TempQueue : X_queue);
		TempPointerQueue = &((!X_queue.empty()) ? TempQueue : X_queue);
		while (!PointerQueue->empty())
		{
			auto data = PointerQueue->front();
			PointerQueue->pop();
			int Isbridge = 0;
			int firstbridge = -1, secondbridge = -1;

			for (auto M : Mover) {
				if (0 > data.first + M[0] || 0 > data.second + M[1] || R <= data.first + M[0] || C <= data.second + M[1])continue;
				if (lake[data.first + M[0]][data.second + M[1]] == Tile::X)
				{
					lake[data.first + M[0]][data.second + M[1]] = Tile::x;
					TempPointerQueue->push({ data.first + M[0] ,data.second + M[1] });
				}
				else if (lake[data.first + M[0]][data.second + M[1]] >= 0) {

					if (Isbridge != 0) {
						Union(lake[data.first][data.second], lake[data.first + M[0]][data.second + M[1]]);
					}
					else {
						Isbridge = lake[data.first + M[0]][data.second + M[1]];
						lake[data.first][data.second] = Isbridge;
					}
				}
			}
		}

		if (UnionFInd(L_Point[0]) == UnionFInd(L_Point[1]))break;


	} while (!TempPointerQueue->empty());
	cout << day;
}



int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);
	SwanLake();

}

 

'알고리즘' 카테고리의 다른 글

전력난 [백준:6497] 골드  (3) 2024.11.14
알고리즘 [flood fill]  (0) 2024.11.12
영우의 기숙사 청소 [백준 : 15806번]  (0) 2024.11.05
부분합 알고리즘  (0) 2024.10.29
타잔(Tarjan) 알고리즘  (0) 2024.07.20
반응형

 

 

 

으른 상어

 

https://www.acmicpc.net/problem/19237

 

 

 

문제의 구조는

입력받기

 

상어의 이동 방향  데이터 받아오기

상어의 이동

상어의 냄새 남기기

 

순서로 진행한다.

 

 

위이미지처럼 1번 상어부터 

오른쪽을 보기에  맨 아래  오른쪽 왼쪽 위아래 순으로 탐색한다.

 

냄새를 남긴다.

 

만약 겹칠 경우 낮은 값을 가진 상어가 이긴다.

 

 

해당 문제를 해결할 때 냄새를 업데이트한다면 시간이 많이 걸릴 것이라 생각했기에 time으로 그냥 계산해 준다.

 

 

 

 

해당 문제에서 26 퍼에서 틀린다면 1000 이상 인지 초과인지  개발 순서의 시간을 언제 업데이트

하는지 확인해야 한다. 

 

 

 

 

#include<iostream>
#include<vector>

using namespace std;
static const int SharkBasic_Mover[4][2] = { {0,-1} ,{0,1}, {-1,0}, {1,0} };
enum direction {
	UP = 0,
	DOWN,
	LEFT,
	RIGHT
};
struct Shark
{
public:
	Shark() {
		Mover = vector<vector<direction>>(4, vector<direction>(4));
		Sharknumber = -1;
		PosX = -1, PosY = -1;
	}

	vector<vector<direction>> Mover;
	direction dir;
	int PosX, PosY, Sharknumber;
	bool IS_Alive = true;
};

void AdultShark() {
	//N*N , M개상어, K냄새 남는시간
	int N = 0, M = 0, K = 0, time = 0;
	//현재시간과 비교해서 사라졌는지 확인
	cin >> N >> M >> K;
	vector< Shark>Sharks(M, Shark());
	vector<vector<pair<int, int>>> World(N, vector<pair<int, int>>(N, make_pair(-1, -1)));
	int num = 0;
	for (int i = 0; i < N; ++i) {
		for (int j = 0; j < N; ++j) {
			cin >> num;
			if (num != 0) {
				Sharks[num - 1].PosX = j;
				Sharks[num - 1].PosY = i;
				Sharks[num - 1].Sharknumber = num - 1;
				World[j][i] = make_pair(num - 1, time);

			}
		}
	}
	//상어방향
	for (int i = 0; i < M; ++i) {
		cin >> num;
		Sharks[i].dir = direction(num - 1);
	}
	//방향우선순위
	for (int i = 0; i < M; ++i) {
		for (int j = 0; j < 4; ++j) {
			for (int k = 0; k < 4; ++k) {
				cin >> num;
				Sharks[i].Mover[j][k] = direction(num - 1);
			}
		}
	}
	vector<direction>* MoveDir;
	int x = 0, y = 0;
	while (M != 1)
	{
		time++;
		//이동할 위치 넣기
		for (Shark& S : Sharks) {
			if (S.IS_Alive == false) continue;
			//move
			MoveDir = &(S.Mover[S.dir]);
			direction nowdir = S.dir;
			int Smellx = -1, Smelly = -1;
			bool ISMove = false;
			for (int i = 0; i < MoveDir->size(); ++i) {

				x = S.PosX + SharkBasic_Mover[(int)((*MoveDir)[i])][0];
				y = S.PosY + SharkBasic_Mover[(int)((*MoveDir)[i])][1];
				if (x < 0 || N <= x || y < 0 || N <= y)continue;
				if (World[x][y].first == -1) {
					S.dir = (*MoveDir)[i];
					S.PosX = x;
					S.PosY = y;
					ISMove = true;
					break;
				}
				else {
					// 현재 -   기록 시간       유지시간
					if (((time - World[x][y].second) > K)) { //  (3time - 1) 2냄새 지남 
						//빈칸취급
						S.dir = (*MoveDir)[i];
						S.PosX = x;
						S.PosY = y;
						ISMove = true;
						break;
					}//                                              선턴
					else if (World[x][y].first == S.Sharknumber && Smellx == -1) {
						Smellx = x;
						Smelly = y;
						nowdir = (*MoveDir)[i];
					}
				}
			}
			//냄새칸 첫위치
			if (ISMove == false) {
				S.PosX = Smellx;
				S.PosY = Smelly;
				S.dir = nowdir;
			}
		}


		for (int i = 0 ; i < Sharks.size();++i)
		{
			Shark& S = Sharks[i];
			if (S.IS_Alive == false) continue;

			if (World[S.PosX][S.PosY].second == time) {
				S.IS_Alive = false;
				M--;
			}
			else
			{
				World[S.PosX][S.PosY] = make_pair(S.Sharknumber, time);
			}
		}

		if (time > 1000) { time = -1; break; }
	}
	cout << time;
}

int main() {


	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);

	AdultShark();
}
반응형

알고리즘 문제 코드 수정후 재빌드 상태에서 강제 취소 했을때

LNK1136 에러가 났다 

 

해당 에러는 빌드시 불러오는 헤더에서 문제가 생긴것으로 추측하고있다.

 

디버그 돌려도 해결되지않는다.

다시 빌드 시 문제가 해결된다.

반응형

 

ctrl +, 또는 ctrl + t  전체 페이지중 이동

 

 

 

ctrl +. :빠른작업  리팩토링

 


ctrl +j :  자동완성 표시

 

 

 

ctrl + r +r : 함수나 변수 명을 한번에 변경

ctrl + k +d : 줄 자동 정렬

 

ctrl + k +c  : 주석 으로 변경

 

ctrl + k + u : 주석 해제 - 하나씩 해제

 

 

ctrl + m + o :  정의 부분만 보이기

 

 

f12 : 정의 탐색

 

 

 

 

shift +f12 : 모든 참조 찾기

 

 

 

디버그 중 중단점이후

f11 : 한단계씩 코드 실행 - 함수내부까지 들어감

f10 : 프로시저  단위 실행

 

 

'언어' 카테고리의 다른 글

증감연산자  (0) 2021.05.31
오버로딩과 오버라이딩  (0) 2021.05.15
메서드 와 함수가 다른가?  (0) 2021.05.15
반응형

cpp 로 백준 문제를 풀다보면 여러가지 팁을 얻을수 있는데

그중에 해당 코드를 볼수있는데

 

std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);

 

해당 코드들은 cpp 입출력 성능을 최적화 하기위해 사용되는 설정들이다.

 


std::ios::sync_with_stdio(false);

는 cpp iostream 과 c의 stdio 를 동기화 하는 설정을 해제한다.

기본적으로 cpp는 c의 printf scanf 등과 호환성을위해 동기화 되어있다.

동기화를 해제하면 cin과 cout 속도가 빨라지지만 printf scanf 와 같이쓸수없다.

 

std::cin.tie(0); 또는std::cin.tie(nullptr); 

cin과 out의 묶음을 해제한다

기본적으로 cin을 사용하기 전에 cout 버퍼를 flush 하는 동작이 묶여있는데 이를 해제한다.

입력받기전에 출력 버퍼를 비울필요가 없어져서 속도가 향상된다.

 

std::cout.tie(0) 또는 std::cout.tie(nullptr)

cout의 tie를 해제한다.

 

cin.tie(0)와 비슷한역활이다.

 

tie는 cpp의 입출력 스트림에서 두스트림을 묶어주는 역활을 하는데

 

cout<<"반가워"

cin>>name;

 

은  내부적으로 사이에 cout.flush 가들어간다. 

 

하지만 tie(0)을 해서 해제하면 사이에 flush없이 바로 입력을 받는다.

 

반응형

#include<iostream>
using namespace std;


int SugarSalt()
{
	int data = 0,answer=0;
	cin >> data;

	while (data!=0)
	{
		if (data % 5 == 0) {
			data -= 5;
			answer++;
		}
		else if (data - 3 >= 0) {
			data -= 3;
			answer++;
		}
		else {
			answer = -1;
			break;
		}
	}
	return answer;
}
int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cin.tie(NULL);
	cout<<SugarSalt();

	return 0;
}

 

+ Recent posts