- 18513번 샘터

 

18513번: 샘터

첫째 줄에 자연수 N과 K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N, K ≤ 100,000) 둘째 줄에 N개의 샘터의 위치가 공백을 기준으로 구분되어 정수 형태로 주어진다. (-100,000,000 ≤ 샘터의 위치 ≤

www.acmicpc.net

<풀이>

일단 평소 처럼 체크배열 쓰려다가 범위가 제대로 안정해져있어서 set을 사용했다.

    -> 조건 범위가 샘터의 위치를 기준으로 -10000000 ~ 10000000  이렇게  입력되는 샘터의 위치마다 다르기 때문에 !!  배열 길이를 제한하기 어려웠다

 

 set 도 set인데 unordered_set이 더 속도가 빠르다 해서 걍 이걸 사용해봄 

 

 

1.  여태 풀었던 숨박꼭질 시리즈와 유사함  약간 숨바꼭질 염불하는 사람같은데  이렇게 일차원으로 입력되는건 어쩔 수 없다 그것만 생각남

2. 방문 체크 배열이 없기 때문에 set로 방문  즉, 이미 샘터가 있거나 집 지은곳을 체크할거임 

3.  샘터위치의 범위를 보면 int는 터질거 같아서  long long type으로 체크

4. 그 이후는 보통 BFS와 탐색방법 똑같다. 대신 집을 지을 수 있는건 샘터 위치를 기준으로 앞뒤로 움직이면서 가능하며  처음 입력된 샘터의 위치를 기준으로 거리를 누적계산하며 더해준다.

 

 

- 처음에 계속 83%에서 틀렸습니다가 나왔는데  내 생각에는  기존 BFS 방식처럼  각 입력되는 샘터 위치의 기준으로 나온 범위를

공통 범위라 생각하여  집이 지어질 수 있는 좌표를 고정으로 제한해서 그런거 같다.  그 부분을 주석 처리하고 재 재출하니까 성공했다.

 

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <unordered_set>

using namespace std;

int n,k;
int dx[2] = {-1,1};
int main(void){
    cin>>n>>k;
    queue<pair<long long,long long> > que;
    unordered_set<long long> st;
    int a;
    for(int i=0; i<n; i++){
        cin>>a;
        que.push(make_pair(a,a));
        st.insert(a);
    }


    long long result = 0;

    while(!que.empty()){
        long long x = que.front().first;
        long long dis = que.front().second;
        que.pop();

        for(int i=0; i<2; i++){
            long long nx = x +dx[i];

            //if(nx<-100000000 || nx>100000000 ) continue;  <- 이 부분 때문에83%에서 틀림
            if(st.count(nx)>=1) continue;

            k-=1;
            result += abs(nx-dis);
            
            if(k==0){
                cout<<result<<"\n";
                return 0;
            }


            que.push(make_pair(nx,dis));
            st.insert(nx);
        }   
    }
}

 

 

 

- 14442번 벽부수고 이동하기2

 

14442번: 벽 부수고 이동하기 2

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 1,000), K(1 ≤ K ≤ 10)이 주어진다. 다음 N개의 줄에 M개의 숫자로 맵이 주어진다. (1, 1)과 (N, M)은 항상 0이라고 가정하자.

www.acmicpc.net

<틀린 풀이>

-첫 번째 접근 : 조합 (전체의 벽중에  K를 선택하여 0으로 바꿔줌) +  BFS탐색  ->  시간 초과

아마 모든 조건을 다 찾아보기 때문에 시간초과가 나는거같다. 

코드 아까워서 시간초과난 코드도 기록함 ㄱ- 

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>

using namespace std;

int n,m,k;
string map[1005];
int ch[1005][1005];
int dx[4] = {-1,0,1,0};
int dy[4] ={0,1,0,-1};
int result = 2147000000;
int BFS(){
    queue<pair<int,int> > que;
    memset(ch,0,sizeof(ch));
    que.push(make_pair(0,0));
    ch[0][0] = 1;

    while(!que.empty()){
        int x = que.front().first;
        int y = que.front().second;
        que.pop();

        if(x== n-1 && y == m-1) {
            return ch[x][y];
        }

        for(int i=0; i<4; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
            if(map[nx][ny]!='0' || ch[nx][ny]!=0) continue;
            que.push(make_pair(nx,ny));
            ch[nx][ny] = ch[x][y]+1;
        }
    }

    return -1;
}

void DFS(int L){
    if(L==k){
      if(BFS() == -1) {
          return;
      }
      else {
          result = min(result,BFS());
          return;
      }
    }
    else{
        for(int i=0; i<n; i++){
            for(int j=0; j<m; j++){
                if(map[i][j] == '1'){
                    map[i][j] = '0';
                    DFS(L+1);
                    map[i][j] = '1';
                }
            }
        }
    }
}

int main(void){
    cin>>n>>m>>k;
    for(int i=0; i<n; i++){
        cin>>map[i];
    }

    DFS(0);
    if(result ==2147000000 ){
        cout<<-1<<"\n";
    }
    else{
        cout<<result<<"\n";
    }
}

 

 

<재 시도한 풀이>

- 예전에 풀었던 벽 부수고 이동하기 처럼  3차원 배열을 사용해서 재 접근했다.

( 왜 처음에 바로 생각을 못했을까 훨씬 간단한 방법이었는데,,, 머릿속에 조합밖에 없었나봄 ㄱ- ㅋㅋㅋㅋ) 

- 벽을 부순 개수 = 즉, 벽인데도 지나간 개수를 따로 배열에 저장하며 탐색했다.

 

탐색 가능한 방법은 2가지 이다. 

공통 조건 :  이동할 위치에 방문하지 않았어야함 

1.  다음 이동할 위치에 벽이 있으며, 벽이 있는데 지나간 개수가 k보다 작다면 탐색할 수 있도록 큐에 넣어준다.

2. 다음 이동할 위치에 벽이 없다면 탐색가능하기 때문에 큐에 넣어준다.

 

따로 거리는 탐색 체크 배열을 이용하여 갱신해주며 탐색했다.

주어진 조건에서 시작점도 탐색 거리를 1로 쳐준다 해서 0,0 위치에 1을 넣고 시작함 !!! 

 

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>

using namespace std;

int n,m,k;
int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};
string map[1005];
int ch[1005][1005][11];
struct State{
    int x,y,wall;
    State(int a, int b, int c){
        x = a;
        y = b;
        wall = c;
    }
};

int BFS(){
    memset(ch,0,sizeof(ch));
    queue<State> que;
    que.push(State(0,0,0));
    ch[0][0][0] = 1;

    while(!que.empty()){
        int x = que.front().x;
        int y = que.front().y;
        int wall = que.front().wall;
        que.pop();

        if(x == n-1 && y== m-1){
            return ch[x][y][wall];
        }

        for(int i=0; i<4; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
            if(ch[nx][ny][wall]!=0) continue;
            if(map[nx][ny]=='1' && wall != k){
                que.push(State(nx,ny,wall+1));
                ch[nx][ny][wall+1] = ch[x][y][wall]+1;
            }
            else if(map[nx][ny]=='0'){
                que.push(State(nx,ny,wall));
                ch[nx][ny][wall] = ch[x][y][wall]+1;
            }
        }
    }
    
    return -1;
}

int main(void){
    cin>>n>>m>>k;
    for(int i=0; i<n; i++){
        cin>>map[i];
    }

    cout<<BFS()<<"\n";
}

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 17일차  (0) 2021.09.05
[ 백준 ] 16일차  (0) 2021.09.03
[ 백준 ] 14일차  (0) 2021.09.01
[ 백준 ] 13일차  (0) 2021.08.31
[ 백준 ] 12일차  (0) 2021.08.30

- 18352번 특정 거리의 도시 찾기

 

18352번: 특정 거리의 도시 찾기

첫째 줄에 도시의 개수 N, 도로의 개수 M, 거리 정보 K, 출발 도시의 번호 X가 주어진다. (2 ≤ N ≤ 300,000, 1 ≤ M ≤ 1,000,000, 1 ≤ K ≤ 300,000, 1 ≤ X ≤ N) 둘째 줄부터 M개의 줄에 걸쳐서 두 개

www.acmicpc.net

<풀이>

어제 구현한 다익스트라를 활용!  입력되는 도시 사이의 거리는 1로 고정이기 때문에 1을 넣어준다. 그 후 x부터 시작하여 갈 수 있는 도시로 최단 거리 탐색을 진행함

탐색이 끝난 후 해당 도시까지의 최단 거리가 k인 도시의 이름만 출력해주면 된다. 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

struct State{
    int pos,dis;
    State(int a, int b){
        pos = a;
        dis = b;
    }

    bool operator<(const State &nn) const{
        return dis>nn.dis;
    }
};
int n,m,k,x;

int main(void){
    cin>>n>>m>>k>>x;
    vector<pair<int,int> > vec[n+1];
    vector<int> dist(n+1, 2147000000);
    priority_queue<State> que;
    int a,b;
    for(int i=0; i<m; i++){
        cin>>a>>b;
        vec[a].push_back(make_pair(b,1));
    }

    que.push(State(x,0));
    dist[x] = 0;

    while(!que.empty()){
        int pos = que.top().pos;
        int dis = que.top().dis;
        que.pop();

        if(dis>dist[pos])continue;

        for(int i=0; i<vec[pos].size(); i++){
            int nxpos = vec[pos][i].first;
            int nxdis = dis + vec[pos][i].second;
            if(dist[nxpos]>nxdis){
                dist[nxpos] = nxdis;
                que.push(State(nxpos,nxdis));
            }
        }
    }

    int cnt = 0;
    for(int i=1; i<=n; i++){
        if(dist[i]==k){
            cout<<i<<"\n";
            cnt++;
        }
    }
    if(cnt == 0){
        cout<<-1<<"\n";
    }
    
    return 0; 

}

 

- 2660번 회장 뽑기

 

2660번: 회장뽑기

입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터

www.acmicpc.net

 

<풀이>

플로이드 와샬 문제를 풀어보았다 ~ 

플로이드 와샬과 다익스트라의 차이점을 잠깐 비교해보자면

- 다익스트라 : 특정 한 정점에서 다른 정점 까지의 최단거리

- 플로이드 와샬 :  모든 정점에서 모든 정점 까지의 최단거리 

 

이번 문제는 회장이 될 수 있는 모든 학생을 찾아야 하기 때문에 플로이드 와샬을 사용하였다.

인접리스트를 사용했던 다익스트라와 달리 인접 행렬 형태로 2차원 배열을 사용하며  최단 거리를 갱신했다.

최단 거리를 갱신하는 방법은  

1. 입력으로 주어지는 a->b로 가는 거리

2. a -> k -> b 처럼 특정 k를 지나고 b로 갈때의 거리

이 둘 중 더 최소인 거리로 인접 행렬을 갱신해주면 된다. 

 

이 문제는 방향성이 없으며 한번 친구면 다른 방향도 친구이기 때문에 ( = 각 정점사이 거리 1 ) 양방향 방식으로 넣어줬다. 

처음에 이부분을 제대로 안잡아줘서.. 문제가 조금 있었다.

 

1. 인접 행렬에 거리 갱신 (자기 자신은 0)

2. 플로이드 와샬 알고리즘을 활용하여 각 최단 거리를 갱신

3. 각 학생의  최댓값을 따로 배열에 저장한다.

4. 학생 리스트 중에 최단 거리를 가진 학생이 회장이 될 수 있기 때문에 이를 구하고 같은 거리를 가진 학생의 수와 학생을 뽑아주면 된다

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int main(void){
    int n;
    cin>>n;
    vector<vector<int> > dist(n+1, vector<int> (n+1, 5000));
    for(int i=1; i<=n; i++) dist[i][i] = 0;
    int a,b;
    while(1){
        cin>>a>>b;
        if(a==-1 && b==-1) break;
        dist[a][b] = 1;
        dist[b][a] = 1;
    }

    for(int k=1; k<=n; k++){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                dist[i][j] = min(dist[i][j], dist[i][k]+dist[k][j]);
            }
        }
    }

    vector<int> res(n+1);
    int ans = 214700000;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            res[i] = max(res[i],dist[i][j]);
        }
        ans = min(ans, res[i]);
    }
    int cnt =0;
    for(int i=1; i<=n; i++){
        if(ans == res[i]) cnt++; 
    }
    cout<<ans<<" "<<cnt<<"\n";
    for(int i=1; i<=n; i++){
        if(ans == res[i]) cout<<i<<" ";
    }
    return 0; 
   
   
}

  

 

- 1389번 케빈 베이컨의 6단계 법칙 

 

1389번: 케빈 베이컨의 6단계 법칙

첫째 줄에 유저의 수 N (2 ≤ N ≤ 100)과 친구 관계의 수 M (1 ≤ M ≤ 5,000)이 주어진다. 둘째 줄부터 M개의 줄에는 친구 관계가 주어진다. 친구 관계는 A와 B로 이루어져 있으며, A와 B가 친구라는 뜻

www.acmicpc.net

<풀이>

이 문제도 플로이드 와샬로 풀어보았다. 

 

1. 인접 행렬 생성 및 초기화

2. 친구 관계 = 양방향 그래프이기 때문에 인접행렬에 넣어준다. 

3. 플로이드 와샬로 각 연결된 친구 관계의 최단 거리를 갱신

4. 인접행렬을 체크하며 각 사람마다 베이컨의 수 합을 더해주며  가장 작은 베이컨의 수를 구한다.

5. 가장 작은 베이컨의 수를 가진 사람 중 제일 번호가 작은 사람 1명만 출력해야하기 때문에 1부터 돌며  출력과 동시에 함수를 종료시켜준다. 

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int main(void){
    int n,m,a,b;
    cin>>n>>m;
    vector<vector<int> > dist(n+1, vector<int>(n+1,5000));
    for(int i=1; i<=n; i++) dist[i][i]=0;
    for(int i=0; i<m; i++){
        cin>>a>>b;
        dist[a][b] = 1;
        dist[b][a] = 1;
    }

    for(int k=1; k<=n; k++){
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                dist[i][j] = min(dist[i][j] , dist[i][k] + dist[k][j]);
            }
        }
    }
    vector<int> res(n+1);
    int ans = 2147000000;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            res[i]+=dist[i][j];
        }
       ans = min(res[i],ans);
    }

    for(int i=1; i<=n; i++){
        if(ans == res[i]){
            cout<<i<<"\n";
            return 0; 
        }
    } 
   
}

 

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 16일차  (0) 2021.09.03
[ 백준 ] 15일차  (0) 2021.09.02
[ 백준 ] 13일차  (0) 2021.08.31
[ 백준 ] 12일차  (0) 2021.08.30
[ 백준 ] 11일차  (0) 2021.08.28

- 1753번 최단경로

 

1753번: 최단경로

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1≤V≤20,000, 1≤E≤300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1≤K≤V)가 주어진다.

www.acmicpc.net

<풀이>

다익스트라를 사용하였다! dist배열을 두어  시작점부터 해당 정점으로 까지의 최소 비용을 저장해두었다.

다익스트라 같은 경우에는 가중치가 양수인 경우에만 사용이 가능하며 그렇기 때문에 이미 출발점으로 선정되어 탐색된 값 자체가 바뀔 확률이 적다!!  이렇게 중복 탐색을 막기위해 따로 체크 배열을 둘 수 도 있지만, 우선순위 큐를 사용하였다.

 

우선순위큐를 통해 최소 힙으로 탐색하며  거리가 제일 작은 것 부터 연결된 모든 정점을 탐색, 기존의 dist배열의 값보다 탐색 비용이 적다면 갱신하고 큐에 넣어주는 방식으로 구현하였다!

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int n,m,k;
struct Edge{
    int pos,dis;
    Edge(int a, int b){
        pos = a;
        dis = b;
    }

    bool operator<(const Edge &nn)const{
        return dis>nn.dis;
    } 
};

int main(void){
    cin>>n>>m;
    cin>>k;
    vector<int> dist(n+1, 2147000000);
    priority_queue<Edge> que;
    vector<pair<int,int> > vec[n+1];
    int a,b,c;
    for(int i=0; i<m; i++){
        cin>>a>>b>>c;
        vec[a].push_back(make_pair(b,c));
    }
    que.push(Edge(k,0));
    dist[k] = 0;

    while(!que.empty()){
        int pos = que.top().pos;
        int dis = que.top().dis;
        que.pop();

        if(dis > dist[pos]) continue;
        for(int i=0; i<vec[pos].size(); i++){
            int nxpos = vec[pos][i].first;
            int nxdis = dis + vec[pos][i].second;

            if(dist[nxpos]>nxdis){
                dist[nxpos] = nxdis;
                que.push(Edge(nxpos,nxdis));
            }
        }
    }

    for(int i=1; i<=n; i++){
        if(dist[i]!=2147000000 ) cout<<dist[i]<<"\n";
        else cout<<"INF"<<"\n";
    }
}

 

- 1238번 파티

 

1238번: 파티

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 10,000), X가 공백으로 구분되어 입력된다. 두 번째 줄부터 M+1번째 줄까지 i번째 도로의 시작점, 끝점, 그리고 이 도로를 지나는데 필요한 소요시간 Ti가 들어

www.acmicpc.net

 

<풀이>

다익스트라를 공부하고 제대로 익히기 위해 풀어본 두 번째 문제..  위에서 푼 다익스트라 문제와 사용한 구조는 아주 유사하다. 단지 차이점이 있다면 다익스트라를 함수로 빼서 두번 사용한 것

 

1. i 위치로 시작하여  x로 가는 최단 거리를 구한다.

2. x위치로 시작하여 각 i로 가는 최단 거리를 구한다.

3. 1,2를 더하며 최댓값을 출력한다. 

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int n,m,x;

struct Edge
{
    int pos, dis;
    Edge(int a, int b){
        pos = a;
        dis = b;
    }

    bool operator<(const Edge &nn) const{
        return dis>nn.dis;
    }
};


vector<pair<int,int> > vec[1005];
   
vector<int> dijkstra(int st){

    vector<int> dist(n+1, 2147000000);
    priority_queue<Edge> que;
    que.push(Edge(st,0));
    dist[st] = 0;

    while(!que.empty()){
        int pos = que.top().pos;
        int dis = que.top().dis;
        que.pop();

        if(dis > dist[pos]) continue;

        for(int i=0; i<vec[pos].size(); i++){
            int nxpos = vec[pos][i].first;
            int nxdis = dis+vec[pos][i].second;

            if(dist[nxpos]>nxdis){
                dist[nxpos] = nxdis;
                que.push(Edge(nxpos,nxdis));
            }
        }
    }
    return dist;
}

int main(void){
    cin>>n>>m>>x;

    int a,b,c;
    for(int i=0; i<m; i++){
        cin>>a>>b>>c;
        vec[a].push_back(make_pair(b,c));
    }
    int ans = -2147000000;

    for(int i=1; i<=n; i++){

        vector<int> tmp = dijkstra(i);
        vector<int> tmp2 = dijkstra(x);

        if(tmp[x]== 2147000000 || tmp2[i] == 2147000000) continue;

        ans = max(ans,tmp[x]+tmp2[i]);

    }
    cout<<ans<<"\n";
}

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 15일차  (0) 2021.09.02
[ 백준 ] 14일차  (0) 2021.09.01
[ 백준 ] 12일차  (0) 2021.08.30
[ 백준 ] 11일차  (0) 2021.08.28
[ 백준 ] 10일차  (0) 2021.08.27

- 2961번 도영이가 만든 맛있는 음식

 

2961번: 도영이가 만든 맛있는 음식

첫째 줄에 재료의 개수 N(1 ≤ N ≤ 10)이 주어진다. 다음 N개 줄에는 그 재료의 신맛과 쓴맛이 공백으로 구분되어 주어진다. 모든 재료를 사용해서 요리를 만들었을 때, 그 요리의 신맛과 쓴맛은

www.acmicpc.net

<풀이>

재귀 함수를 사용함  초기 쓴맛과 신맛의 각 합(곱/덧셈)을 구하고 하나씩 빼주면서 차이의 최솟값을 갱신해준다. 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>


using namespace std;

int n;
long long arr[11][11];
long long ch[11];
long long ts =1, tb= 0;
long long result = 214700000;

void DFS(int L, long long ss, long long bb ){
    if(L == n){
        return;
    }
    if(result > abs(ss-bb)){
        result = abs(ss-bb);
    }
    else{
        for(int i=0; i<n; i++){
            if(!ch[i]){
                 ch[i] = 1;
                DFS(L+1, ss/arr[i][0], bb-arr[i][1]);
                ch[i] = 0;
            }
        }
    }
}

int main(void){
    cin>>n;
    for(int i=0; i<n; i++){
        cin>>arr[i][0]>>arr[i][1];
        ts *= arr[i][0];
        tb += arr[i][1];
    }
    result = abs(ts-tb);
    DFS(0,ts,tb);
    cout<<result<<"\n";
}

 

- 18232번 텔레포트 정거장

 

18232번: 텔레포트 정거장

첫 번째 줄에 정수 N, M이 공백으로 구분되어 주어진다. (2 ≤ N ≤ 300,000, 0 ≤ M ≤ min(N×(N-1)/2, 300,000)) 두 번째 줄에 정수 S, E가 공백으로 구분되어 주어진다. (1 ≤ S, E ≤ N, S ≠ E) 그 다음 줄부터 M

www.acmicpc.net

<풀이>

BFS를 사용한  숨바꼭질 시리즈와 유사한 문제.. 

여러번 시도를 했는데 틀린 이유는 텔레포트의 정거장 이동방법을 단방향만 가능하다 생각하고 풀어서 틀렸다. 벡터에 양방향으로 넣어서 풀어주니 성공..~

 

1. x-1 이동

2. x+1 이동

3. 텔레포트 이동 (양방향 이동가능)

 

이 3가지 조건에 대해 BFS탐색을 할 수 있도록 구현해주면 된다.

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int n,m;
int ch[300001];
vector<int> vec[300001];

int main(void){
    cin>>n>>m;
    int s,e;
    cin>>s>>e;
    for(int i=0; i<m; i++){
        int x,y;
        cin>>x>>y;
       vec[x].push_back(y);
       vec[y].push_back(x);
    }

    queue<pair<int,int> > que;
    que.push(make_pair(s,0));
    ch[s] = 1;


    while(!que.empty()){
        int x = que.front().first;
        int cnt = que.front().second;
        que.pop();
       
        if(x == e){
            cout<<cnt<<"\n";
            return 0;
        }

        if(x-1>0 && !ch[x-1]){
            ch[x-1] = 1;
            que.push(make_pair(x-1,cnt+1));
        }

        if(x+1<=n && !ch[x+1]){
            ch[x+1] = 1;
            que.push(make_pair(x+1,cnt+1));
        }

       for(int i=0; i<vec[x].size(); i++){
           if(!ch[vec[x][i]]){
               ch[vec[x][i]] =1;
               que.push(make_pair(vec[x][i],cnt+1));
           }
       }
        
    }
}

 

- 18404번 현명한 나이트 

 

18404번: 현명한 나이트

첫째 줄에 N과 M이 공백을 기준으로 구분되어 자연수로 주어진다. (1 ≤ N ≤ 500, 1 ≤ M ≤ 1,000) 둘째 줄에 나이트의 위치 (X, Y)를 의미하는 X와 Y가 공백을 기준으로 구분되어 자연수로 주어진다. (

www.acmicpc.net

<풀이>

로직 자체는 안어려웠는데 처음 접근 방식에 계속 시간초과가 떠서.. 다시 엎었다

첫 번째 접근법은 , m개의  상대편 말의 위치가 입력될 때 마다 BFS탐색을 돌면서 각 요소의 개수를 벡터에 저장하는 식으로 구현을 했었다.

아마 매번 M개 만큼 BFS 탐색을 해야하기 때문에 거리를 체크할 체크 배열 초기화 과정이 필요했다. memset을 사용했지만, 2차원이고 만약 m이 1000 이면 제한 조건인 1초가 넘는 2초가 걸리기 때문에 시간초과가 나오는 걸로 판단했다.

 

두 번째 접근법은 어처피 M개의 말이 입력되어도 모든 경우의 나이트 위치가 x,y로 고정이라는 점을 활용했다.

그렇기 때문에 x,y나이트의 위치에서 전체 탐색 1번 을 하고 각 말의 위치의 값을 출력해주는 방식으로 수정했다.

이런 경우 배열의 초기화 과정이 필요없고, 탐색 또한 1번으로 끝내며 입력되는 말의 위치에 각 저장된 탐색 거리만 출력하면 되기 때문에 확실하게 탐색 시간을 줄일 수 있었다...! 휴,,

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int dx[8] ={1,2,2,1,-1,-2,-2,-1};
int dy[8] ={2,1,-1,-2,-2,-1,1,2};

int n,m,X,Y;
int map[505][505],ch[505][505];


void BFS(int a, int b){
    queue<pair<int,int> > que;
    que.push(make_pair(a,b));
    ch[a][b] = 1;

    while(!que.empty()){
        int x = que.front().first;
        int y = que.front().second;
        que.pop();
        for(int i=0; i<8; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx<0 || nx>=n || ny<0 || ny>=n) continue;
            if(ch[nx][ny]!=0 ) continue;
            que.push(make_pair(nx,ny));
            ch[nx][ny] = ch[x][y]+1;
        }
    }
}

int main(void){
    cin>>n>>m;
    cin>>X>>Y;
    BFS(X-1,Y-1);
    for(int i=0; i<m; i++){
        cin>>X>>Y;
        cout<<ch[X-1][Y-1]-1<<" ";
    }
    cout<<"\n";
}

 

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 14일차  (0) 2021.09.01
[ 백준 ] 13일차  (0) 2021.08.31
[ 백준 ] 11일차  (0) 2021.08.28
[ 백준 ] 10일차  (0) 2021.08.27
[ 백준 ] 9일차  (0) 2021.08.25

- 7562번 나이트의 이동

 

7562번: 나이트의 이동

체스판 위에 한 나이트가 놓여져 있다. 나이트가 한 번에 이동할 수 있는 칸은 아래 그림에 나와있다. 나이트가 이동하려고 하는 칸이 주어진다. 나이트는 몇 번 움직이면 이 칸으로 이동할 수

www.acmicpc.net

<풀이> 

- 나이트가 이동할 수 있는 좌표를 넣어준다.

- BFS를 돌며 나이트가 이동할 수 있을 경우 큐에 넣어주고 이동 거리를 갱신해주며  원하는 지점에 도착한 경우 벡터에 넣어줌

 

-> 포인트는 테스트 케이스 횟수만큼 배열 사이즈와 나이트, 나이트가 이동할 칸의 위치가 한 번에 입력되기 때문에 매 차례마다 갱신해주어야한다는 점! 

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int dx[8] ={1,2,2,1,-1,-2,-2,-1};
int dy[8] ={2,1,-1,-2,-2,-1,1,2};
int n;
int ch[305][305];
vector<int> vec;

void BFS(int xx,int yy , int aa, int bb){
    memset(ch,-1,sizeof(ch));
    queue<pair<int,int> > que;
    que.push(make_pair(xx,yy));
    ch[xx][yy] =0;

    while(!que.empty()){
        int x = que.front().first;
        int y = que.front().second;
        que.pop();

        if(x  == aa && y == bb){
            vec.push_back(ch[x][y]);
            break;
        }

        for(int i=0; i<8; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];

            if(nx<0 || nx>=n  || ny<0 || ny>=n) continue;
            if(ch[nx][ny] !=-1) continue;
            que.push(make_pair(nx,ny));
            ch[nx][ny] = ch[x][y]+1;
        }
    }
}


int main(void){
    int t;
    cin>>t;
    int a,b,c,d;
    while(t--){
        cin>>n;
        cin>>a>>b;
        cin>>c>>d;
        BFS(a,b,c,d);
    }

    for(int i=0; i<vec.size(); i++){
        cout<<vec[i]<<"\n";
    }

    return 0;
}

 

 

- 12761번 돌다리

 

12761번: 돌다리

동규와 주미는 일직선 상의 돌 다리 위에있다. 돌의 번호는 0 부터 100,000 까지 존재하고 동규는 \(N\)번 돌 위에, 주미는 \(M\)번 돌 위에 위치하고 있다. 동규는 주미가 너무 보고싶기 때문에 최대

www.acmicpc.net

<풀이>

- 예전에 풀었던 숨바꼭질 시리즈와 아주 유사한 문제였다.

- 주어진 8개의 이동 조건에 따라 각 조건식을 세워주고 탐색 가능하는 경우 ( 0이상인 경우 / 100000 이하인 경우) 탐색을 진행하고 탐색 횟수를 증가 시켜준다

 

- 주어진 이동조건과  이동 가능 범위만 제대로 체크하면 쉬운 문제 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int ch[100001];
int n,m,a,b;

int main(void){
    cin>>a>>b>>n>>m;
    queue<pair<int, int> > que;
    que.push(make_pair(n,0));
    ch[n] = 1;

    while(!que.empty()){
        int x  = que.front().first;
        int cnt = que.front().second;
        que.pop();

        if(x == m){
            cout<<cnt<<"\n";
            return 0;
        }


        if(x+1<100001 && !ch[x+1]){
            que.push(make_pair(x+1,cnt+1));
            ch[x+1] = 1;
        }
        if(x-1>=0 && !ch[x-1]){
            que.push(make_pair(x-1,cnt+1));
            ch[x-1] = 1;
        }


        if(x+a<100001 && !ch[x+a]){
            que.push(make_pair(x+a,cnt+1));
            ch[x+a] = 1;
        }

        if(x-a>=0 && !ch[x-a]){
            que.push(make_pair(x-a,cnt+1));
            ch[x-a] = 1;
        }

         
        if(x+b<100001 && !ch[x+b]){
            que.push(make_pair(x+b,cnt+1));
            ch[x+b] = 1;
        }

        if(x-b>=0 && !ch[x-b]){
            que.push(make_pair(x-b,cnt+1));
            ch[x-b] = 1;
        }


        if(x*a<100001 && !ch[x*a]){
            que.push(make_pair(x*a,cnt+1));
            ch[x*a] = 1;
        }
        if(x*b<100001&& !ch[x*b]){
            que.push(make_pair(x*b,cnt+1));
            ch[x*b] = 1;
        }
    }
}

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 13일차  (0) 2021.08.31
[ 백준 ] 12일차  (0) 2021.08.30
[ 백준 ] 10일차  (0) 2021.08.27
[ 백준 ] 9일차  (0) 2021.08.25
[ 백준 ] 8일차  (0) 2021.08.23

어제 올렸어야했는데 풀다가 때려치고 오늘 재도전 ㄱ- ㅋㅋㅋㅋㅋ

 

- 17836번 공주님을 구해라! 

 

17836번: 공주님을 구해라!

용사는 마왕이 숨겨놓은 공주님을 구하기 위해 (N, M) 크기의 성 입구 (1,1)으로 들어왔다. 마왕은 용사가 공주를 찾지 못하도록 성의 여러 군데 마법 벽을 세워놓았다. 용사는 현재의 가지고 있는

www.acmicpc.net

얘 땜에 어제 약간 멘탈 나갈뻔 .. 처음엔 배열 하나에 단순히 검 위치를 지나고 공주님 위치로 가면 당연히 최단 거리인 줄 알고  bool 타입 변수를 둬서 벽 상관없이 다 지나게 구하는 식으로 했더니  당연히 ^^ 틀렸다.

-> 1. 검을 안지나고 탐색했을 때 최단거리 가 나올 수 있는 상황도 존재하기 때문에 

-> 2. 검을 새로 갖게된 경우 검 없을 때 지났던 곳도 지날 수 있음

=> 즉, 검 위치를 지날때와 안지날 때 두가지의 상황을 모두 구해야함 

 

그래서 체크 배열을 3차원으로 두고 검을 지나면 검을 안지났을 때 까지의 거리를 다 옮겨서 검 지난걸로 탐색하는걸로 했지만 왜인지 테케랑 질문 목록에 있는 반례 1개 빼고 다 통과... 1개는 왜인지 도저히 이해가 안가서  어젠 걍 포기하고 오늘 재도전..

오늘 새로운 접근법은 다음과 같다.  최대한 코드 재활용 가능하고 간편하게 하려고..고민좀 해봤다.

<풀이> 

문제의 큰 틀은  (0,0) -> (n-1, m-1 ) 위치에 도달할 때의 최단 거리이다.

즉 , 2가지 방법이 존재함 

1. (0,0) 부터 시작해서  검을 안지나고 (n-1,m-1)  도달하는 경우

2. (0,0)부터 시작해서 검을 만나고 (n-1, m-1)에 도달하는 경우

 

1번 같은 경우에는 매번 했던 BFS처럼 벽이거나 이미 지났으면 패스 하고  탐색 못했으면 214700000을 리턴하게함

-> 최단거리를 구해야하기 때문에 도착 못하면 일부러 터무니없는 값으로 설정함

 

2번은  매번 초기화하는게 번거롭기 때문에  (0,0) 부터  검위치 까지 도달한 거리와   검위치 에서 도착지점까지의 각 x,y 좌표 차이를 더해줬다. 

어처피 검을 지난경우  벽에 상관없이 지날 수 있기 때문에  단순히 좌표 차이의 합으로도 이동거리가 나오기 때문에!!

 

3. 마지막으로는 두가지 방법으로 탐색했을 떄의 최소 거리 값이 주어진 t시간보다 작은지 확인하는 과정 필요 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int n,m,t;
int map[105][105],ch[105][105];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

int BFS(int a, int b){
    memset(ch,-1,sizeof(ch));
    queue<pair<int,int> > que;
    que.push(make_pair(0,0));
    ch[0][0]= 0;
    while(!que.empty()){
        int x = que.front().first;
        int y = que.front().second;
        que.pop();
        if(x == a && y == b){
            return ch[x][y];
        }
        for(int i=0; i<4; i++){
            int nx = x + dx[i];
            int ny = y + dy[i];
            if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
            if(map[nx][ny]==1 || ch[nx][ny] !=-1) continue;
            que.push(make_pair(nx,ny));
            ch[nx][ny] = ch[x][y]+1;
        }
    }

    return 21470000; 
}

int main(void){
    cin>>n>>m>>t;
    pair<int,int> pr;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            cin>>map[i][j];
            if(map[i][j] == 2){
                pr.first = i;
                pr.second = j;
            }
        }
    }
    int newn = n-1;
    int newm = m-1;
    int ans = min(BFS(newn,newm), BFS(pr.first,pr.second)+ (newn-pr.first) + (newm-pr.second));
    if(ans<0 || ans>t) {
        cout<<"Fail"<<"\n";
    }
    else cout<<ans<<"\n";
}

 

- 2668번 숫자고르기 

 

2668번: 숫자고르기

세로 두 줄, 가로로 N개의 칸으로 이루어진 표가 있다. 첫째 줄의 각 칸에는 정수 1, 2, …, N이 차례대로 들어 있고 둘째 줄의 각 칸에는 1이상 N이하인 정수가 들어 있다. 첫째 줄에서 숫자를 적절

www.acmicpc.net

<풀이>

- DFS를 돌며  사이클이 발생하는 수와 그 요소들을 벡터에 넣어서 출력해주면 된다 

- 1부터 탐색해서 들어가기 때문에 정렬은 필요 없다 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;

int n;
int p[101],ch[101];
vector<int> vec;

void DFS(int start,int cur){
    if(!ch[cur]){
        ch[cur] = 1;
        DFS(start,p[cur]);
    }
    else if(cur == start){
        vec.push_back(cur);
        return;
    }
}

int main(void){
    cin>>n;
    for(int i=1; i<=n; i++){
        cin>>p[i];
    }

    for(int i=1; i<=n; i++){
        memset(ch,0,sizeof(ch));
        DFS(i,i);
    }   
    cout<<vec.size()<<"\n";
    for(int i=0; i<vec.size(); i++){
        cout<<vec[i]<<"\n";
    }
    return 0; 
}

 

 

- 13565번 침투

 

13565번: 침투

첫째 줄에는 격자의 크기를 나타내는  M (2 ≤ M ≤ 1,000) 과 N (2 ≤ N ≤ 1,000) 이 주어진다. M줄에 걸쳐서, N개의 0 또는 1 이 공백 없이 주어진다. 0은 전류가 잘 통하는 흰색, 1은 전류가 통하지 않

www.acmicpc.net

그림을 보고 바깥쪽과 안쪽의 위치를 잘 파악해주면서 구현하면 된다.

<풀이>

- 바깥쪽 :  map[0][0 ~ m-1] 

- 안쪽 : map [n-1][0~ m-1]

 

여러 방법이 있지만, 나는 침투하는 위치의 좌표를 2로 바꿔주면서 진행했다.

1. 바깥쪽을 체크하며 0인 부분에 침투 됐다는 표시로 좌표 값을 2로 바꿔주며 상하좌우 탐색

2. 안쪽을 체크하며  하나라도 2가 존재한다면 (=침투 됐다면) YES를 출력, 아니라면 NO를 출력한다.

 

주의할 부분은 입력값이 공백없이 쫙 들어오기 때문에 나처럼 2차원 int타입의 배열로 cin 사용해 받는 경우 ide에서는 문제가 발생했따. 그래서 걍  string으로 입력받으면서 처리함 

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int n,m;
string map[1005];
int ch[1005][1005];
int dx[4] = {-1,0,1,0};
int dy[4] ={0,1,0,-1};
int main(void){
    cin>>n>>m;

    for(int i=0; i<n; i++){
        cin>>map[i];
    }

    for(int i=0; i<m; i++){
        if(map[0][i] == '0'){
            map[0][i] = '2';
        }
    }
    queue<pair<int,int> > que;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(map[i][j] == '2' && !ch[i][j]){
                que.push(make_pair(i,j));
                ch[i][j] = 1;

                while(!que.empty()){
                    int x = que.front().first;
                    int y = que.front().second;
                    que.pop();
                    for(int i=0; i<4; i++){
                        int nx = x +dx[i];
                        int ny = y +dy[i];

                        if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
                        if(map[nx][ny] == '1' || ch[nx][ny] !=0) continue;
                        que.push(make_pair(nx,ny));
                        ch[nx][ny] = 1;
                        map[nx][ny] = '2';
                    }
                }
            }
        }
    }

    for(int i=0; i<m; i++){
        if(map[n-1][i] == '2'){
            cout<<"YES"<<"\n";
            return 0;
        }
    }
    cout<<"NO"<<"\n";
}

 

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 12일차  (0) 2021.08.30
[ 백준 ] 11일차  (0) 2021.08.28
[ 백준 ] 9일차  (0) 2021.08.25
[ 백준 ] 8일차  (0) 2021.08.23
[ 삼성대비 ] 7일차  (0) 2021.08.22

- 16918번 봄버맨

 

16918번: 봄버맨

첫째 줄에 R, C, N (1 ≤ R, C, N ≤ 200)이 주어진다. 둘째 줄부터 R개의 줄에 격자판의 초기 상태가 주어진다. 빈 칸은 '.'로, 폭탄은 'O'로 주어진다.

www.acmicpc.net

<풀이>

1. 1초 인 경우 초기 입력 값 출력

2. 짝수 초 (2,4,6,8 ... ) 경우 모든 칸에 'O'을 넣어줌

3. 1 외에 홀 수인 경우 초기 O 과 상하좌우 자리에 '.' 을 넣어준다. 

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
int n,m,k;
string map[205];
int dx[4] ={-1,0,1,0};
int dy[4] = {0,1,0,-1};

int main(void){
    cin>>n>>m>>k;
    queue<pair<int,int> > que;
    for(int i=0; i<n; i++){
        cin>>map[i];
    }
    
    if(k==1){
        for(int i=0; i<n; i++){
            cout<<map[i]<<"\n";
        }
        return 0;
    }
    else{
        for(int i=2; i<=k; i++){
            if(i%2 ==0){
                for(int x=0; x<n; x++){
                    for(int y=0; y<m; y++){
                        if(map[x][y] == 'O'){
                            que.push(make_pair(x,y));
                        }
                        else{
                            map[x][y] = 'O';
                        }
                    }
                }
            }
            else{
                while(!que.empty()){
                    int x =que.front().first;
                    int y = que.front().second;
                    que.pop();
                    map[x][y] ='.';
                    for(int i=0; i<4; i++){
                        int nx = x +dx[i];
                        int ny = y + dy[i];

                        if(nx<0 || nx>=n || ny<0 || ny>=m)continue;
                        map[nx][ny] = '.';
                    }
                }
            }
            
        }
    
    }
    for(int i=0; i<n; i++){
        cout<<map[i]<<"\n";
    }
    return 0; 
    

}

 

 - 17129번 윌리암슨수액빨이딱따구리가 정보섬에 올라온 이유

 

17129번: 윌리암슨수액빨이딱따구리가 정보섬에 올라온 이유

첫째 줄에 정보섬 2층의 크기 n과 m이 주어진다. (1 ≤ n,m ≤ 3000, 4 ≤ n×m ≤ 9×106) 이후 n행 m열에 걸쳐 0, 1, 2, 3, 4, 5로만 구성된 Ai,j가 주어진다. Ai,j와 Ai,j+1사이에 공백은 주어지지 않는다. 2,

www.acmicpc.net

문제이름이 너무 시강이라 함 풀어봄  로직 자체는 엄청 쉬웠는데 문제를 제대로 안읽고 ... 딱따구리 가족의 시작 지점을 못찾아서 시간을 조금 소요함.. ㅠㅋㅋㅋㅋ 요근래 책을 잘 안읽었더니 독해력이 바닥났나... 어질어질 

 

<풀이>

1. BFS탐색을 돌면서  딱따구리의 가족위치인 '2'에서 부터 탐색을 진행한다.

2. 진행하며 만나는 위치의 값이 3,4,5 중에 하나라면 TAK를 출력하고 그곳까지의 거리를 출력함

초기 위치를 0이라고 주어졌는데 나같은 경우는 1로 설정해서  출력할떄 -1를 해줬다.

3. 그외에  while문을 출력하면서 까지 조건에 도덜하지 못한다면 NIE를 출력한다.

 

로직 자체는 어렵지 않은데, 아마 배열의 사이즈가 커서 scanf로 받는다면 시간초과가 날 거같다. 나는 어처피 cin을 쓰기도 하고.. 혹시나 하는 마음에 그래서  string 으로 받으며 시간초과를 대비했다. 이부분 때문에 골드 레벨의 문제가 아닐까..?하는 작은 생각...

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
int n,m;

int dx[4] ={-1,0,1,0};
int dy[4] = {0,1,0,-1};
int ch[3003][3003];
string map[3003];
int main(void){
    cin>>n>>m;
    for(int i=0; i<n; i++){
        cin>>map[i];
    }
    queue<pair<int,int> > que;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
           if(map[i][j] == '2' && !ch[i][j]){
               que.push(make_pair(i,j));
               ch[i][j] = 1;

               while(!que.empty()){
                   int x = que.front().first;
                   int y = que.front().second;
                   que.pop();
                   if( map[x][y]=='3' || map[x][y] == '4' || map[x][y]=='5'){
                       cout<<"TAK"<<"\n"<<ch[x][y]-1<<"\n";
                       return 0;
                   }

                   for(int i=0; i<4; i++){
                       int nx = x +dx[i];
                       int ny = y +dy[i];

                       if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
                       if(map[nx][ny] == '1' || ch[nx][ny]!=0) continue;
                       que.push(make_pair(nx,ny));
                       ch[nx][ny] = ch[x][y]+1;
                   }
               }
            }
        }
    }
    cout<<"NIE"<<"\n";
    return 0;
}

 

 

- 14716번 현수막

 

14716번: 현수막

혁진이의 생각대로 프로그램을 구현했을 때, 현수막에서 글자의 개수가 몇 개인지 출력하여라.

www.acmicpc.net

<풀이>

1. 상하좌우 대각선까지 고려하여 탐색진행

2. 탐색하며 1이며 방문하지 않은 지점만 탐색

3. 탐색이 끝나고 새로운 곳으로 다시 탐색이 시작되면 횟수를 증가시킨다 = 글자의 수 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
int n,m;
int dx[8] = { -1,-1,0,1,1,1,0,-1};
int dy[8] = { 0,1,1,1,0,-1,-1,-1};
int map[300][300],ch[300][300];

int main(void){
    cin>>n>>m;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            cin>>map[i][j];
        }
    }

    queue<pair<int,int> > que;
    int cnt = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(map[i][j] == 1 && !ch[i][j]){
                que.push(make_pair(i,j));
                ch[i][j] = 1;
                 cnt++;
                while(!que.empty()){
                    int x = que.front().first;
                    int y = que.front().second;
                    que.pop();

                    for(int i=0; i<8; i++){
                        int nx  = x+dx[i];
                        int ny = y +dy[i];

                        if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
                        if(map[nx][ny] == 0 || ch[nx][ny]!=0) continue;
                        que.push(make_pair(nx,ny));
                        ch[nx][ny] = 1;
                    }
                }
               
            }
        }
    }

    cout<<cnt<<"\n";
}

 

 

- 11123번 양 한마리...양 두마리...

 

11123번: 양 한마리... 양 두마리...

얼마전에 나는 불면증에 시달렸지... 천장이 뚫어져라 뜬 눈으로 밤을 지새우곤 했었지.  그러던 어느 날 내 친구 광민이에게 나의 불면증에 대해 말했더니 이렇게 말하더군. "양이라도 세봐!"  

www.acmicpc.net

내일부터는 지옥의 골드레벨의 그래프 탐색만 풀 예정이니... 쉬어가는 겸 실버만 조진다...레벨 의미 없다지만,,, 그래도 실버 1이니까 ....괜찮아...

<풀이> 

솔직히 그래프 탐색 문제가 거기서 거기인 느낌인거 같지만...사실이다. ㄱ-

이 문제의 특이점은  문자열로 구성되어 있다는것과.. 뭐 양이 2마리 이상이면 하나의 양 무리로 본다는데 결국 그말은 위에 문제처럼  모든 양의 위치에서 탐색할 수 있는 횟수 자체를 구해주면 된다..... ㄱ- 

 

로직은 어렵지 않으며  주의할 점은 T만큼의 예제를 한번에 넣어주기 때문에  매 새로운 입력을 받아올 때 마다 map과 방문 체크 배열, 탐색을 위한 큐, 카운트 변수 등의 초기화가 가장 중요하다.  그부분만 유의하면 큰 문제는 없는 문제! 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
int t,n,m;
int dx[4] ={-1,0,1,0};
int dy[4]= {0,1,0,-1};
string map[105];
int ch[105][105];


int main(void){
    cin>>t;
    while(t--){
        string map[105];
        memset(ch,0,sizeof(ch));
        int cnt = 0;
        cin>>n>>m;
        for(int i=0; i<n; i++){
            cin>>map[i];
        }
        queue<pair<int,int> > que;
        for(int i=0; i<n; i++ ){
            for(int j=0; j<m; j++){
                if(map[i][j] == '#' && !ch[i][j]){
                    que.push(make_pair(i,j));
                    ch[i][j] = 1;
                    cnt++;
                    while(!que.empty()){
                        int x = que.front().first;
                        int y = que.front().second;
                        que.pop();

                        for(int i=0; i<4; i++){
                            int nx = x +dx[i];
                            int ny = y +dy[i];

                            if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
                            if(map[nx][ny]=='.' || ch[nx][ny] !=0) continue;
                            que.push(make_pair(nx,ny));
                            ch[nx][ny] = 1;
                        }
                    }
                }
            }
        }
        cout<<cnt<<"\n";
    }
}

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 11일차  (0) 2021.08.28
[ 백준 ] 10일차  (0) 2021.08.27
[ 백준 ] 8일차  (0) 2021.08.23
[ 삼성대비 ] 7일차  (0) 2021.08.22
[ 삼성대비 ] 6일차  (0) 2021.08.21

삼성대비 인척,,, 삼성 기출 나머지 약 20개 문제가 넘 어려워서 일단 BFS/DFS랑 다른 시뮬문제좀 도전하면서 구현력좀 기르고,,, 다시 할라고  BFS/DFS 문제 도전.... ㄱ- 

 

- 1303 전쟁-전투 

 

1303번: 전쟁 - 전투

첫째 줄에는 전쟁터의 가로 크기 N, 세로 크기 M(1 ≤ N, M ≤ 100)이 주어진다. 그 다음 두 번째 줄에서 M+1번째 줄에는 각각 (X, Y)에 있는 병사들의 옷색이 띄어쓰기 없이 주어진다. 모든 자리에는

www.acmicpc.net

<풀이>

이 문제 처럼 실버 문제는 솔직히 큰 어려움 없이 푸는데,,,,, 골드는 왜이리 어렵니 ~~~~~~

그냥 각 W로만 탐색할 때 /  B로 탐색할 때  각 두가지의 이동 영역을 벡터에 저장해서 각 값을 곱하고 더해주면 된다

사실 함수로 하나 만들어서 코드 중복을 줄여야하는데  넘 귀찮아서 걍 노답 코드로 사용함.... 가독성0과 길이만 겁나 길어진 나의 코드...ㅋㅋㅋㅋㅋㅋㅋㅋ  

1. W로 탐색하면서  상하좌우 지나갈 수 있는 영역 벡터에 저장

2.  B기준으로 탐색하며 상하좌우 지날 수 있는 영역의 수 벡터 저장

3. 각 1,2번의 영역 수의 제곱의 합 구해서 출력하기

 

로직은 굉장히 쉬워서 10분도 안걸린거 같은데 계속 틀렸습니다가 나와서 확인해보니  문제에 가로 세로 표현이 반대로 나와있어서... 18%에서 계속 틀렸다 ㅠ ㅋㅋㅋㅋㅋㅋㅋ 아오 ~ 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};
string map[105];
int ch[105][105];
int n,m;
int main(void){
    cin>>m>>n;
    for(int i=0; i<n; i++){
        cin>>map[i];
    }

    vector<int> vec;
    queue<pair<int,int> > wq;
    queue<pair<int,int> > bq;
    int area =0;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(map[i][j] == 'W' && !ch[i][j]){
                wq.push(make_pair(i,j));
                ch[i][j] = 1;
                area = 0;
                while(!wq.empty()){
                    int x = wq.front().first;
                    int y = wq.front().second;
                    wq.pop();
                    area++;
                    for(int i=0; i<4; i++){
                        int nx = x + dx[i];
                        int ny = y + dy[i];
                        if(nx <0 || nx>=n || ny<0 || ny>=m) continue;
                        if(map[nx][ny]=='B' || ch[nx][ny]!=0) continue;
                        wq.push(make_pair(nx,ny));
                        ch[nx][ny] = 1;
                    }
                }
                vec.push_back(area);
            }
        }
    }
    int w = 0;
    for(int i=0; i<vec.size(); i++){
        if(vec[i]>0){
        w = w + vec[i]*vec[i];
        }
    }
    vec.clear();
    memset(ch,0,sizeof(ch));
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            if(map[i][j] == 'B' && !ch[i][j] ){
                bq.push(make_pair(i,j));
                ch[i][j] = 1;
                area =0;
                while(!bq.empty()){
                    int x = bq.front().first;
                    int y = bq.front().second;
                    bq.pop();
                    area++;
                    for(int i=0; i<4; i++){
                        int nx = x+ dx[i];
                        int ny = y +dy[i];
                        if(nx<0 || nx>=n || ny<0 || ny>=m) continue;
                        if(map[nx][ny]=='W' || ch[nx][ny]!=0) continue;
                        bq.push(make_pair(nx,ny));
                        ch[nx][ny] =1;
                    }
                }
                vec.push_back(area);
            }
        }
    }
    int b =0;
    for(int i=0; i<vec.size(); i++){
        if(vec[i]>0)
        b = b+ vec[i]*vec[i];
    }
    cout<<w<<" "<<b<<"\n";
}

 

- 16953번 A->B

 

16953번: A → B

첫째 줄에 A, B (1 ≤ A < B ≤ 109)가 주어진다.

www.acmicpc.net

<풀이> 

A->B로 가는 최소 횟수를 구하는 문제

유사한 문제가 많아서 B->A로 거꾸로 풀어도 되지만 DFS를 사용했다. 여기서 포인트는 A,B의 범위가 10^9 이기 때문에 타입을 long long 으로 설정해주어야 한다는 것... 

사실 처음에 범위를 안보고  예전에 풀었던  숨바꼭질 시리즈 처럼 체크 배열두고 풀다가 터짐ㅠ ㅋㅋㅋㅋㅋㅋㅋㅋ 

문제를 꼼꼼히 읽자......

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;
long long a,b;
long long minN = 214700000;

void DFS(long long num, long long cnt){
    if(num>b) return;
    if(num==b){
        minN = min(minN,cnt);
        return;
    }
    else{
        DFS(num*2, cnt+1);
        DFS(num*10+1, cnt+1);
    }
}
int main(void){
    cin>>a>>b;
    DFS(a,1);
    if(minN == 214700000) cout<<-1<<"\n";
    else cout<<minN<<"\n";
}

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 10일차  (0) 2021.08.27
[ 백준 ] 9일차  (0) 2021.08.25
[ 삼성대비 ] 7일차  (0) 2021.08.22
[ 삼성대비 ] 6일차  (0) 2021.08.21
[ 삼성대비 ] 5일차  (0) 2021.08.20

- 20056 마법사 상어와 파이어볼  

 

20056번: 마법사 상어와 파이어볼

첫째 줄에 N, M, K가 주어진다. 둘째 줄부터 M개의 줄에 파이어볼의 정보가 한 줄에 하나씩 주어진다. 파이어볼의 정보는 다섯 정수 ri, ci, mi, si, di로 이루어져 있다. 서로 다른 두 파이어볼의 위치

www.acmicpc.net

<풀이>

오늘도 시뮬레이션..문제  

시뮬레이션 특징처럼 주어진 조건을 차례대로 구현을 해주면 된다. 풀면서 분명 로직은 맞았는데 계속 태케 4번에서 9가 아닌 12가 나오길래 정말 3번정도 지우고 다시 풀었는데  알고보니.... 방향 배열에 한 요소를 1인데 -1로 넣어서.....하..ㅋㅋ..ㅋㅋㅋㅋ.....ㅋㅋ..... 역시 오늘도 삽질 ^^....ㅋㅋ....인생 쓰다 ~

 

1. 주어진 방향으로 전환해서 이동하기 때문에  방향예시를 보고 차례대로 배열에 넣어줌 

2. 파이어볼에 대해 위치, 질량,속력,방향을 저장해주어아 하기 때문에 구조체를 따로 생성

3. 파이어볼이 이동하고, map에 넣어주는 부분 구현

  3-1. 파이어볼이 저장된 벡터의 사이즈만큼 돌면서 이동거리를 구해준다  =  현위치 + 방향 * 속력 

   -> 여기서 이동 거리가  맵을 벗어날때에 대한 예외처리가 필요하다... 배열크기 보다 작으면 크기만큼 더해주고, 크기보다 크면 빼준다

  3-2. 맵에 이동한 파이어볼의 정보를 넣어준다. 

4. 맵을 돌면서 한 칸에 2개이상의 파이어볼이 존재한다면 더하고 나누는 부분 구현

  4-1. 파이어볼이 0이면 그냥 패스 1개면 바로 다른 벡터에 넣어줌

  4-2. 파이어볼 개수가 해당 칸에 2개이상이라면  질량의 합과, 속력의 합을 구해주고  해당 방향이 유일한 짝수/홀수 인지 판단 진행

  4-3. 4-2의 판단에 따라 새로운 질량,속력, 위치, 방향을  조건에 따라 넣어준다.

    +  새로운 질량이 0인 경우  소멸되어 없어지기 때문에 이 부분에 대한 예외처리 필요 

  4-4.  저장된 내용의 파이어볼을 다시 벡터에 넣어주기

5. K 번 위의 연산을 진행하고 남은 파이어볼의 질량의 합을 구해서 출력하기 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>


using namespace std;

int dx[8] = { -1,-1,0,1,1,1,0,-1};
int dy[8] = { 0,1,1,1,0,-1,-1,-1};
struct State{
    int x,y,m,s,d;
    State(){};
    State(int a,int b, int c, int e, int f){
        x = a;
        y = b;
        m = c;
        s = e;
        d = f;
    }
};
vector<State> map[55][55];
vector<State> vec;
int n,m,k;

int main(void){
    cin>>n>>m>>k;
    for(int i=0; i<m; i++){
        int x,y,m,s,d;
        cin>>x>>y>>m>>s>>d;
        vec.push_back(State(x-1,y-1,m,s,d));
    }
    while(k--){
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                map[i][j].clear();
            }
        }
        //1. 파이어볼 이동 & 저장
        for(int i=0; i<vec.size(); i++){
            State tmp = vec[i];
            int nx = tmp.x + dx[tmp.d]*tmp.s;
            int ny = tmp.y + dy[tmp.d]*tmp.s;
            while(nx<0) nx+=n;
            while(ny<0) ny+=n;
            while(nx>=n) nx-=n;
            while(ny>=n) ny-=n;
            map[nx][ny].push_back(State(nx,ny,tmp.m,tmp.s,tmp.d));
        }

        //2. 파이어볼 합치고 분리 
        vector<State> tmp;
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                if(map[i][j].size()==0) continue;
                if(map[i][j].size()==1) tmp.push_back(map[i][j][0]);
                else{
                    bool od = false, ev = false;
                    int msum =0, ssum =0;
                    for(int k=0; k<map[i][j].size(); k++){
                        msum += map[i][j][k].m;
                        ssum += map[i][j][k].s;
                        if(map[i][j][k].d % 2==0) ev=true;
                        else od = true;
                    }
                    int mnew = msum/5;
                    int snew = ssum/map[i][j].size();

                    if(mnew == 0) continue;
                    if(!od || !ev){
                        tmp.push_back(State(i,j,mnew,snew,0));
                        tmp.push_back(State(i,j,mnew,snew,2));
                        tmp.push_back(State(i,j,mnew,snew,4));
                        tmp.push_back(State(i,j,mnew,snew,6));
                    }
                    else{
                        tmp.push_back(State(i,j,mnew,snew,1));
                        tmp.push_back(State(i,j,mnew,snew,3));
                        tmp.push_back(State(i,j,mnew,snew,5));
                        tmp.push_back(State(i,j,mnew,snew,7));
                    }
                }
            }
        }
        vec = tmp;
    }
    int sum = 0;
    for(int i=0; i<vec.size(); i++){
        sum+=vec[i].m;
    }
    cout<<sum<<"\n";
}

 

- 1743번 음식물 피하기

 

1743번: 음식물 피하기

첫째 줄에 통로의 세로 길이 N(1 ≤ N ≤ 100)과 가로 길이 M(1 ≤ M ≤ 100) 그리고 음식물 쓰레기의 개수 K(1 ≤ K ≤ N×M)이 주어진다.  그리고 다음 K개의 줄에 음식물이 떨어진 좌표 (r, c)가 주어진다

www.acmicpc.net

<풀이>

앞 문제에 너무 많은 힘을 쏟아내서 무난하고 귀여운 BFS문제를 풀었다..

1. 입력되는 음식물 쓰레기의 좌표를 표시 

2. 음식물 쓰레기 위치부터 탐색을 진행하며  한 번에 탐색이 되는 (상하좌우에 존재하는) 음식물의 개수를 세어준다 

3. 최댓값을 매 새로운 쓰레기 위치에서 탐색할 때 마다 갱신해주면 끝

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

int dx[4] = {-1,0,1,0};
int dy[4] = {0,1,0,-1};
int n,m,k;
int map[101][101],ch[101][101];
int main(void){
    cin>>n>>m>>k;
    queue<pair<int,int> > que;
    for(int i=0; i<k; i++){
        int x,y;
        cin>>x>>y;
        map[x-1][y-1] = 2;
    }
    int ans =0;

   for(int i=0; i<n; i++){
       for(int j=0; j<m; j++){
           if(map[i][j]==2 && !ch[i][j]){
               que.push(make_pair(i,j));
               ch[i][j] = 1;
                int area =0;
               while(!que.empty()){
                   int x = que.front().first;
                   int y = que.front().second;
                   que.pop();
                    area++;
                   for(int k=0; k<4; k++){
                       int nx = x+dx[k];
                       int ny = y +dy[k];
                       if(nx<0 || nx>=n || ny<0 || ny>=m)continue;
                       if(map[nx][ny] == 0 || ch[nx][ny]>0) continue;
                       que.push(make_pair(nx,ny));
                       ch[nx][ny] = ch[x][y]+1;
                   }
               }
               ans = max(ans,area);
           }
       }
   }

   
   cout<<ans<<"\n";

}

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 9일차  (0) 2021.08.25
[ 백준 ] 8일차  (0) 2021.08.23
[ 삼성대비 ] 6일차  (0) 2021.08.21
[ 삼성대비 ] 5일차  (0) 2021.08.20
[ 삼성대비 ] 4일차  (0) 2021.08.19

- 17140번 이차원 배열과 연산 

 

17140번: 이차원 배열과 연산

첫째 줄에 r, c, k가 주어진다. (1 ≤ r, c, k ≤ 100) 둘째 줄부터 3개의 줄에 배열 A에 들어있는 수가 주어진다. 배열 A에 들어있는 수는 100보다 작거나 같은 자연수이다.

www.acmicpc.net

<풀이> 

오늘도 지옥의 시뮬레이션 문제 .. 

주어진 조건대로 각 R연산/  C연산을 구현한다.

C연산의 경우에는 R연산을 구현하고 행x열 위치만 바꾸면 되기 때문에 큰 무리는 없었다. 

초기 행/열의 크기를 3으로 고정하고 연산을 진행하였다.

각 행/열에 대한 숫자의 개수와, 해당 숫자를 저장해두어야 하기 때문에 벡터 pair형식을 사용하였다. 

 

1. R연산 

1.1 벡터를 선언하며 행 단위로 배열을 탐색하며  나오는 요소의 횟수를 세어준다.

1.2 조건대로 0으로 채워진 부분은 세어줄 필요 없기 때문에 1부터 개수가 있는 대로 벡터에 넣어준다.

1.3  맵에 벡터로 저장되어 갱신될 요소를 저장하기 위해  0으로 초기화 진행한다.

1.4 row의 개수만큼 정렬을 진행

-> 정렬 조건

   1. 개수가 커지는 순서대로 (즉 오름차순)

   2. 개수가 같다면 수가 커지는 순서대로 (=오름차순) 

=> pair형식을 정렬할 경우  first를 우선으로  오름차순 (기본 정렬이 오름차순) 정렬하고, first가 같다면 second를 기준으로 정렬 하기 때문에 first에 해당 숫자의 출연 횟수를 저장했다. 

1.5 벡터에 저장되어 정렬된 요소를 맵에 넣어준다. 

+ 개수가 100을 넘는 경우 버려주어야하는 조건을 위해 99이상이면 반복문을 멈춰줌 

+ 넣어주면서 열의 길이를 갱신해줌 

 

2. C연산  

- R의 연산과 로직은 동일

 

3. ( r,c)위에 k가 있는지 확인하는 과정 필요 -> 도달하면 break

4. 100번을 넘게 해도 (r,c)위에 k값이 없으면 break. = -1리턴 

 

- 모든 테케도 통과하고 , 문제는 제대로 풀었지만  계속 42%에서 틀렸습니다가 나와서 질문도 검색하면서.. 삽질좀 했다... 

혹시나 해서 예제 1번처럼  입력되었을 때, 연산 로직을 지나지 않고  바로 (r,c)위에 k값을 찾을 수 있으면 0을 출력하고 끝내는 로직을 추가하니 무사히 통과하였다.... 

괜히 오지랖으로 질문 검색에 나와같은 42%에서 고민하는 사람이 있어서 오지랖부리면서 댓도 남겼다 ㅋㅅㅋ..ㅋㅋㅋㅋㅋㅋㅋ

 

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;

int r,c,k;
int map[105][105];

int main(void){
    cin>>r>>c>>k;
    r--;
    c--;
    for(int i=0; i<3; i++){
        for(int j=0; j<3; j++){
            cin>>map[i][j];
            if(map[r][c] == k){
                cout<<0<<"\n";
                return 0; 
            }
        }
    }
    int row = 3;
    int col = 3;
    int ans = 0;
    while(1){
        ans ++;
        if(ans>100){
            ans = -1;
            break;
        } 
       
        if(row>=col){
            vector<pair<int,int> > vec[105];
            for(int i=0; i<row; i++){
                int cnt[101]={0,};
                for(int j=0; j<col; j++){
                    cnt[map[i][j]]++;
                }
                for(int j=1; j<=100; j++){
                    if(cnt[j]>0){
                        vec[i].push_back(make_pair(cnt[j],j));
                    }
                }
            }
            for(int i=0; i<row; i++){
                for(int j=0; j<col; j++){
                    map[i][j] = 0;
                }
            }
            
            for(int i=0; i<row; i++){
                sort(vec[i].begin(),vec[i].end());
            }
            for(int i=0; i<row; i++){
                int idx = 0;
                for(int j=0; j<vec[i].size(); j++){
                    if(idx>=99) break;
                    map[i][idx++] = vec[i][j].second;
                    map[i][idx++] = vec[i][j].first;
                }
                col = max(col,idx);
            }

        }
        else{
            vector<pair<int,int> > vec[105];
            for(int i=0; i<col; i++){
                int cnt[101] ={0,};
                for(int j=0; j<row; j++){
                    cnt[map[j][i]]++;
                }   

                for(int j=1; j<=100; j++){
                    if(cnt[j]>0){
                        vec[i].push_back(make_pair(cnt[j],j));
                    }
                }
            }

            for(int i=0; i<row; i++){
                for(int j=0; j<col; j++){
                    map[i][j] = 0;
                }
            }

            for(int i=0; i<col; i++){
                sort(vec[i].begin(),vec[i].end());
            }

            for(int i=0; i<col; i++){
                int idx = 0;
                for(int j=0; j<vec[i].size(); j++){
                    if(idx >= 99) break;
                    map[idx++][i] = vec[i][j].second;
                    map[idx++][i] = vec[i][j].first;
                }
                row = max(row,idx);
            }

        }
        if(map[r][c] == k){
            break;
        }
    }
    cout<<ans<<"\n";
}

 

 

'Algorithm > BOJ' 카테고리의 다른 글

[ 백준 ] 8일차  (0) 2021.08.23
[ 삼성대비 ] 7일차  (0) 2021.08.22
[ 삼성대비 ] 5일차  (0) 2021.08.20
[ 삼성대비 ] 4일차  (0) 2021.08.19
[ 삼성대비 ] 3일차  (0) 2021.08.17

+ Recent posts