- 9205번 맥주 마시면서 걸어가기

 

9205번: 맥주 마시면서 걸어가기

송도에 사는 상근이와 친구들은 송도에서 열리는 펜타포트 락 페스티벌에 가려고 한다. 올해는 맥주를 마시면서 걸어가기로 했다. 출발은 상근이네 집에서 하고, 맥주 한 박스를 들고 출발한다.

www.acmicpc.net

<풀이>

최단거리 문제집에 있어서 최단거리로 풀려고 했는데.. 접근 법이 떠오르지 않았다. 그래서 그냥 DFS로 풀었다.

주어진 조건을 보면 맥주 1병에 50미터를 갈 수 있다 햇으니 20병이 최대라면 항상 1000미터 까지 밖에 가지 못한다.

입력되는 좌표의 거리들을 비교하며 1000미터 이하로 갈 수 있다면 도달 가능하다는 것이기 때문에 이러한 좌표들을 인접리스트에 넣은 후 DFS 탐색을 해주었다. 

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;

int t, n;
int ch[105];
vector<int> vec[105];

int dist(pair<int,int> p1, pair<int,int> p2){
    return abs(p1.first-p2.first)+abs(p1.second - p2.second);
}

void DFS(int x){
    for(int i=0; i<vec[x].size(); i++){
        int nx = vec[x][i];
        if(!ch[nx]){
            ch[nx] = 1;
            DFS(nx);
        }
    }
}

int main(void){
    cin>>t;
    while(t--){
        for(int i=0; i<106; i++){
            vec[i].clear();
        }
        memset(ch,0,sizeof(ch));

        cin>>n;
        vector<pair<int,int> > v;
        for(int i=0; i<n+2; i++){
            int a,b;
            cin>>a>>b;
            v.push_back(make_pair(a,b));
        }

        for(int i=0; i<n+2; i++){
            for(int j=i+1; j<n+2; j++){
                if(dist(v[i],v[j])<=1000){
                    vec[i].push_back(j);
                    vec[j].push_back(i);
                }
            }
        }
        DFS(0);

        if(ch[n+1]){
            cout<<"happy"<<"\n";
        }else cout<<"sad"<<"\n";
    }
}

 

-14284번 간선 이어가기 2

 

14284번: 간선 이어가기 2

정점 n개, 0개의 간선으로 이루어진 무방향 그래프가 주어진다. 그리고 m개의 가중치 간선의 정보가 있는 간선리스트가 주어진다. 간선리스트에 있는 간선 하나씩 그래프에 추가해 나갈 것이다.

www.acmicpc.net

<풀이>

오랜만에 다익스트라 문제 ! 양방향 그래프에 다 다른 가중치가 입력 되었고, 두 정점이 연결 되는 시점의 가중치 합의 최솟값 출력하라는 부분을 보고 바로 다익스트라 문제임을 떠올릴 수 있었다. 

 

입력되는 정점 s로 탐색을 시작하며 지점이 t에 도달했을 때의 가중치 합을 출력해주면 된다.

너무 오랜만에 풀어서 그런지.. 가중치 더 하는 부분을 빼먹어서 ^^,,,, 로직을 다시 살펴보았다.... 다시 풀어보길 잘했네..

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#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,s,t;


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

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

        if(dis>dist[pos]) continue;
        if(pos == t){
            cout<<dis<<"\n";
            return 0;
        }
        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));
            }
        }
    }
    

}

 

오늘도 완전탐색 문제

 

-12919번 A와 B2 

 

12919번: A와 B 2

수빈이는 A와 B로만 이루어진 영어 단어 존재한다는 사실에 놀랐다. 대표적인 예로 AB (Abdominal의 약자), BAA (양의 울음 소리), AA (용암의 종류), ABBA (스웨덴 팝 그룹)이 있다. 이런 사실에 놀란 수빈

www.acmicpc.net

<풀이>

첫 접근은 s를 t에 맞게 하나씩 추가하면서 탐색하는 걸로 구현했더니 시간초과가 떴다. 

두번 째 접근은 t에서 하나씩 지워가며 s와 같은지 비교하는 방식으로 구현했다.

 

탐색의 종료조건은 t가 s 의 길이와 같다면 그리고 완전 일치하면 리턴 으로 넣었다.

그 외에는 반대로 진행되기 때문에 주어진 조건을 뒤집어서 생각해주면 된다..

1. 뒤에 A가 있으면 A 삭제하고 탐색

2. 앞에 B가 있으면 B 삭제하고 뒤집어서 매개변수로 넣고 탐색 

 

시간 계산에 약해서 시간초과를 꼭 한 번은 겪네.. 흠...

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>


using namespace std;

string s,t;
int ans;

void DFS(string str){
    if(str.size() == s.size()){
        bool check = true;
        for(int i=0; i<str.size(); i++){
            if(str[i] != s[i]){
                check = false;
            }
        }
        if(check){
            ans = 1;
            return;
        }
    }
    else{
        if(str.back() == 'A'){
            string tmp = str;
            tmp.erase(tmp.size()-1);
            DFS(tmp);
        }
        if(str.front() == 'B'){
            string tmp = str;
            tmp.erase(tmp.begin());
            reverse(tmp.begin(),tmp.end());
            DFS(tmp);
        }
    }
}

int main(void){
    cin>>s;
    cin>>t;
    DFS(t);

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

 

- 16173/16174번  점프왕 쩰리 (Small)/(Large)

 

16173번: 점프왕 쩰리 (Small)

쩰리는 맨 왼쪽 위의 칸에서 출발해 (행, 열)로 나타낸 좌표계로,  (1, 1) -> (2, 1) -> (3, 1) -> (3, 3)으로 이동해 게임에서 승리할 수 있다.

www.acmicpc.net

<풀이>

아래, 오른쪽만 탐색이 가능한 BFS 문제라 쉽게 구현했는데 자꾸 틀려서 확인해보니..

 int y = que.front().first; 로 씀 ㅋㅋㅋㅋㅋ아 ㅋㅋㅋㅋㅋㅋㅋㅋ열받네...

Small / Large 둘다 로직은 다 똑같고, 배열의 크기만 다름.. 뭐징....흠냐.. 

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

int dx[2]={0,1};
int dy[2]={1,0};
int map[4][4],ch[4][4];

int n;

int main(void){
    cin>>n;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            cin>>map[i][j];
        }
    }
    queue<pair<int,int> > que;
    que.push(make_pair(0,0));
    ch[0][0] = 1;
    bool check  = false;
    while(!que.empty()){
        int x = que.front().first;
        int y = que.front().second;
        int move = map[x][y];
        que.pop();

        if(map[x][y] ==-1) {
            cout<<"HaruHaru"<<"\n";
            check = true;
            break;
        }

        for(int i=0; i<2; i++){
            int nx = x + dx[i]*move;
            int ny = y + dy[i]*move;
            if(nx<0 || nx>=n || ny<0 || ny>=n) continue;
            if(ch[nx][ny]) continue;
            que.push(make_pair(nx,ny));
            ch[nx][ny] = 1;
        }
    }
    if(!check){
        cout<<"Hing"<<"\n";
        return 0;
    }
    else return 0;
    

}

-2422번 한윤정이 이탈리아에 가서 아이스크림을 사먹는데

 

2422번: 한윤정이 이탈리아에 가서 아이스크림을 사먹는데

첫째 줄에 정수 N과 M이 주어진다. N은 아이스크림 종류의 수이고, M은 섞어먹으면 안 되는 조합의 개수이다. 아래 M개의 줄에는 섞어먹으면 안 되는 조합의 번호가 주어진다. 같은 조합은 두 번

www.acmicpc.net

<풀이>

DFS +백트래킹 문제였다. 

초기에 매번 구현했떤 식으로 했더니 계속 9%에서 시간초과가 났다.. 이유는 아직도 모르겠음..

그래서 그냥 ch배열에 값 자체를 넣는대신 벡터에 넣어주는 식으로 변형해서 구현했다... 뭔 차이지.. 아직도 모르겠네..

초반에 놓친 부분은 조합을 m 개로 뽑는걸로 알고 구현함... 알고보니 3이었다..

전체적인 구조는 3개의 조합을 뽑고, 그러한 조합에서  사전에 받은 섞어먹으면 안되는 조합의 번호와 비교해서 일치하면 개수를 세어주지 않고 넘기는 식으로 구현했다..

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>


using namespace std;

int n,m,a,b;
int arr[201][201];
int ch[201];
vector<int> vec;
int ans;

void DFS(int L, int s){
    if(L==3){
        for(int i=0; i<vec.size(); i++){
            for(int j=0; j<vec.size(); j++){
                if (i==j) continue;
                if(arr[vec[i]][vec[j]] || arr[vec[j]][vec[i]]) return;
            }
        }
        ans++;
        return;
    }

    else{
        for(int i=s; i<=n; i++){
            if(!ch[i]){
                vec.push_back(i);
                ch[i] = 1;
                DFS(L+1, i+1);
                ch[i] = 0;
                vec.pop_back();
            }
        }
    }
}

int main(void){
    ios_base :: sync_with_stdio(false); 
    cin.tie(NULL); 
    cout.tie(NULL);
    cin>>n>>m;
    for(int i=0; i<m; i++){
        cin>>a>>b;
        arr[a][b] = 1;
        arr[b][a] = 1;
    }

    DFS(0,1);
    cout<<ans<<"\n";

}

 

- 5568번 카드 놓기

 

5568번: 카드 놓기

예제 1의 경우 상근이는 11, 12, 21, 112, 121, 122, 212를 만들 수 있다.

www.acmicpc.net

<풀이>

dfs를 활용한 순열로 놓을 수 있는 카드의 경우를 체크해줌

중복체크는 set 자료구조 활용 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;


int n,k;
int ch[10],map[100];
set<string> st;

void DFS(int L, string str){
    if(L==k){
        st.insert(str);
        return;
    }
    else{
        for(int i=0; i<n; i++){
            if(!ch[i]){
                ch[i] = 1;
                DFS(L+1, str+to_string(map[i]));
                ch[i] =0;
            }
        }
    }
}

int main(void){
    cin>>n;
    cin>>k;
    for(int i=0; i<n; i++){
        cin>>map[i];
    }
    DFS(0,to_string(map[0]));
    cout<<st.size()<<"\n";
   
}

 

- 18511번 큰 수 구성하기 

 

18511번: 큰 수 구성하기

첫째 줄에 N, K의 원소의 개수가 공백을 기준으로 구분되어 자연수로 주어진다. (10 ≤ N ≤ 100,000,000, 1 ≤ K의 원소의 개수 ≤ 3) 둘째 줄에 K의 원소들이 공백을 기준으로 구분되어 주어진다. 각

www.acmicpc.net

<풀이>

문제 포인트는 1-3 까지의 개수를 선택했을 때의 모든 경우의 수를 다 체크해야한다.. 그래서 완탐 문제였나보군..

중복순열인줄 알고 깊이가 k일 때의 경우의 수만 비교했더니 틀렸었따..

내가 완탐에 약해서 그런지 실버 문제에서도 놓치는게 너무 많네... 흠..냐.....

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>


using namespace std;

int n,k,a;
vector<int> vec;
int ans;
void DFS(int num, int sum){
    if(num>n) return;
    
    ans = max(ans,num);

    for(int i=0; i<k; i++){
        DFS(num+sum*vec[i], sum*10);
    }
}

int main(void){
    cin>>n>>k;
    for(int i=0; i<k; i++){
        cin>>a;
        vec.push_back(a);
    }
    
    sort(vec.begin(),vec.end());
    DFS(0,1);
    cout<<ans<<"\n";
}

- 11478번 서로 다른 부분 문자열의 개수

 

11478번: 서로 다른 부분 문자열의 개수

첫째 줄에 문자열 S가 주어진다. S는 알파벳 소문자로만 이루어져 있고, 길이는 1,000 이하이다.

www.acmicpc.net

<풀이>

set사용 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <set>

using namespace std;

int main(void){
    string str;
    cin>>str;
    set<string> st;
    string tmp="";

    for(int i=0; i<str.size(); i++){
        for(int j=i; j<str.size(); j++){
            tmp+=str[j];
            st.insert(tmp);
        }
        tmp="";
    }
   
   cout<<st.size()<<"\n";
   
}

 

- 17219번 비밀번호 찾기

 

17219번: 비밀번호 찾기

첫째 줄에 저장된 사이트 주소의 수 N(1 ≤ N ≤ 100,000)과 비밀번호를 찾으려는 사이트 주소의 수 M(1 ≤ M ≤ 100,000)이 주어진다. 두번째 줄부터 N개의 줄에 걸쳐 각 줄에 사이트 주소와 비밀번

www.acmicpc.net

<풀이>

map  사용   site에 맞는 pwd를 출력해주어야 하기 때문에 site를 key값으로 받는 map을 사용했다

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <map>

using namespace std;

int main(void){
    cin.tie(NULL);
    ios::sync_with_stdio(false);

    int n,m;
    map<string, string> mp;
    cin>>n>>m;
    string site,pwd;

    for(int i=0; i<n; i++){
        cin>>site>>pwd;
        mp.insert(make_pair(site,pwd));
    }

    for(int i=0; i<m; i++){
        cin>>site;
        cout<<mp[site]<<"\n";
    }
}

 

- 6118번 숨바꼭질

 

6118번: 숨바꼭질

재서기는 수혀니와 교외 농장에서 숨바꼭질을 하고 있다. 농장에는 헛간이 많이 널려있고 재서기는 그 중에 하나에 숨어야 한다. 헛간의 개수는 N(2 <= N <= 20,000)개이며, 1 부터 샌다고 하자.   재

www.acmicpc.net

<풀이>

인접리스트로 입력받으며 BFS 탐색으로 진행했다. 최대한 냄새가 안나는 곳 = 가장 멀리 있는 곳 

문제를 착각한 부분은

1. 1번부터 탐색한다는 걸 놓침 (모든 1-N 부분에 대해 시작점으로 두고 탐색을..해버림)

2. 최대한 냄새가 안나는 곳의 개수인데 해당 좌표를 출력하라는 줄 알고 출력함 ...

 

정신이 없어서 그런가.. 쉬운데도 너무 많은걸 놓쳤다.... tmi로 책을 너무 안읽어ㅓㅅ 그런가 조금 긴 내용을 읽으면 놓치는 부분이 너무 많은거 같다.....흠 ^^..

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>

using namespace std;


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

int main(void){
    cin>>n>>m;
    vector<int> vec[n+1];
    queue<int> que;
    for(int i=0; i<m; i++){
        cin>>a>>b;
        vec[a].push_back(b);
        vec[b].push_back(a);
    }
    que.push(1);
    ch[1] = 1;
    int maxNum = -21470000;
    while(!que.empty()){
        int x = que.front();
        que.pop();

        for(int i=0; i<vec[x].size(); i++){
            int nx = vec[x][i];
            if(ch[nx]) continue;
            que.push(nx);
            ch[nx] = ch[x]+1;
            maxNum = max(maxNum,ch[nx]);
        }
    }
    int number = 0;
    int cnt =0;
    for(int i=1; i<=n; i++){
        if(maxNum == ch[i]){
            number = i;
            break;
        }
    }

    for(int i=1; i<=n; i++){
        if(maxNum == ch[i]) cnt++;
    }

    cout<<number<<" "<<maxNum-1<<" "<<cnt<<"\n";
}

 

- 11866번 요세푸스 문제0

 

11866번: 요세푸스 문제 0

첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 1,000)

www.acmicpc.net

<풀이>

deque를 사용했다. 사실 queue 로 해도 문제는 없을거 같은데 수정하기 귀찮아서  deque로 함..

그림을 그려서 진행상황을 보면 알겠지만, front에서 pop을  k-1번 했을 때의 top부분이 우리가 제거하길 원하는 번호이다.

그렇기 때문에 큐가 비어있을 때 까지 k-1번만  top을 뒤로 넣어주고 나서의 top을 따로 벡터에 넣어준다.

그담에 출력하면 끝

 

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string>
#include <vector>
#include <deque>


using namespace std;

int n,k;

int main(void){
    cin>>n>>k;
    k--;
    deque<int> que;
    vector<int> vec;
    for(int i=1; i<=n; i++){
        que.push_back(i);
    }

    while(!que.empty()){
        for(int i=0; i<k; i++){
            que.push_back(que.front());
            que.pop_front();
        }

        vec.push_back(que.front());
        que.pop_front();
    }

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

 

- 18405번 경쟁적 전염

 

18405번: 경쟁적 전염

첫째 줄에 자연수 N, K가 공백을 기준으로 구분되어 주어진다. (1 ≤ N ≤ 200, 1 ≤ K ≤ 1,000) 둘째 줄부터 N개의 줄에 걸쳐서 시험관의 정보가 주어진다. 각 행은 N개의 원소로 구성되며, 해당 위치

www.acmicpc.net

<풀이>

접근 자체는 그렇게 어렵지 않았찌만, 시간초과 어택에 너무 당해서 결국 코드를 밀고 다시 짰다.

문제를 다시 천천히 읽어보면 정말 굳이 큐에 넣어서 탐색 할 이유가 없었따.

바이러스가 있는 지점에서의 상하좌우로만 퍼지면 되는 것이기 때문에 위치 좌표만 넣어서 작은 값이 먼저 확산되도록 정렬만 진행해서 탐색하면 되는 문제였다.

또한, 굳이 체크 배열을 두지 않고 바로 map의 값을 바꿔주면서 진행주면 됐다. 

 

내가 생각하기에 시간초과가 났던 이유는 

1. 매 차례 모든 배열의 값을 다시 첨부터 체크하면서 바이러스 위치를 넣고, 정렬해줌

2. 오름차순으로 확산된다고 했지만, 중간에 이미 원하는 좌표의 점에 값이 있다면 break 를 해주는 부분을 안함.. 

3. 내 생각으로는 굳이 큐에 넣고, 벡터 값 확인하고 하면서 중첩된 for문으로 시간초과가 넘지 않았나 하는 생각...

+ 나의 가독성 떨어지는 ...코드 ^^...

 

매번 클린하게 짜고 싶은데 정신차려보면 ㅈㄴ 개발새발 지저분한 코드가 된다. 꼭 적어도 한 번은 틀리고 다시 밀어야 그제서야 볼만한 코드가 나오는 거 같네... 쉽지않네

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>


using namespace std;

int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1};

struct State{
    int num, x,y;
    State(int n, int a, int b){
        num = n;
        x = a;
        y = b;
    }
    bool operator<(const State &nn) const{
        return num<nn.num;
    }
};
int N,K,S,X,Y;
int map[205][205];
vector<State> vec;
int main(void){
    cin>>N>>K;
    for(int i=0; i<N; i++){
        for(int j=0; j<N; j++){
            cin>>map[i][j];
            if(map[i][j]) vec.push_back(State(map[i][j],i,j));
        }
    }

    sort(vec.begin(),vec.end());

    cin>>S>>X>>Y;
    X--;
    Y--;

    while(S--){
        int len = vec.size();

        for(int i=0; i<len; i++){
            State tmp = vec[i];

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

                if(nx<0 || nx>=N || ny<0 || ny>=N) continue;
                if(map[nx][ny]) continue;
                map[nx][ny] = tmp.num;
                vec.push_back(State(tmp.num,nx,ny));
            }
        }

        if(map[X][Y]) break;
    }

    cout<<map[X][Y]<<"\n";
}

 

 

- 4358번 생태학

 

4358번: 생태학

프로그램은 여러 줄로 이루어져 있으며, 한 줄에 하나의 나무 종 이름이 주어진다. 어떤 종 이름도 30글자를 넘지 않으며, 입력에는 최대 10,000개의 종이 주어지고 최대 1,000,000그루의 나무가 주어

www.acmicpc.net

<풀이>

map을 이용한 문제였다. 로직자체에 어려움은 없었지만, 문자열이 입력될 개수가 명시되어 있지 않고, eof가 올때 까지 계속 입력받으며 공백을 포함한 문자열을 어떻게 입력 받을 부분만 잘 생각해주면 되는 문제였다.

 

일단 c++경우 공백이 있는 문자열을 받아오기 위해서는 getline()메소드를 사용한다.

그런데 입력 될 때 eof 가 왔는지 판별을 어떻게 하나 했더니 geline(cin, str)의 경우  str eof가 오면 eof bit을 설정해 읽기를 중지시킨다고 한다.  다른 예로는 cin.eof()가 true가 됐는지 체크하는 방식도 있었다.

 

일단 나무 종 이름을 입력받아 map을 사용해 개수를 세어준다. 따로 정렬이 필요한 줄 알았는데, map의 경우 first 값을 기준으로 알아서 사전 순 정렬이 기본이라고 한다. 그래서 따로 정렬을 안해주고, 바로 전체에서 차지하는 비율을 소숫점 4자리 까지 출력해주었다.

 

예전에 c++에 공백포함 문자열 입력받을 ㅈ때 gets안되는거 모르고 어리둥절 했던 기억나네... 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <string>

using namespace std;

int main(void){
  map<string, float> mp; 
  string str;
  int cnt = 0;
  while(getline(cin,str)){
      cnt++;
      mp[str]++;
  }

  for(map<string,float> ::iterator iter = mp.begin(); iter!=mp.end(); iter++){
      cout<<iter->first<<" ";
      float num = (iter->second)/cnt*100;
      printf("0.4f\n",num);
  }
  return 0;
}

 

- 9375번 패션왕 신해빈

 

9375번: 패션왕 신해빈

첫 번째 테스트 케이스는 headgear에 해당하는 의상이 hat, turban이며 eyewear에 해당하는 의상이 sunglasses이므로   (hat), (turban), (sunglasses), (hat,sunglasses), (turban,sunglasses)로 총 5가지 이다.

www.acmicpc.net

<풀이>

나의 얄팍한 수학 실력을 느낄 수 있었다. 이항계수 기억조차 안나서 뭔가했네..

이 문제는 의상 자체보다는 의상 종류가 중요하다. 의상 종류의 개수를 map을 이용해서 세어주고 연산 진행하면 된다...

이항계수.....언제 배운거냐...기억도 안나...

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <string>

using namespace std;

int t,n;

int main(void){
    cin>>t;
    while(t--){
        cin>>n;
        map<string,int> mp;
        while(n--){
            string s1,s2;
            cin>>s1>>s2;
            mp[s2]++;
        }
        int ans = 1;
        for(map<string,int> ::iterator iter = mp.begin(); iter!=mp.end(); iter++){
                ans = ans*(iter->second+1);
        }
        cout<<ans-1<<"\n";
        
    }
}

 

- 17086번 아기 상어2

 

17086번: 아기 상어 2

첫째 줄에 공간의 크기 N과 M(2 ≤ N, M ≤ 50)이 주어진다. 둘째 줄부터 N개의 줄에 공간의 상태가 주어지며, 0은 빈 칸, 1은 아기 상어가 있는 칸이다. 빈 칸의 개수가 한 개 이상인 입력만 주어진다.

www.acmicpc.net

<풀이>

오랜만에 푸는 그래프탐색 문제! 오랜만이라 그런지 문제 잘못읽어서 잘못 구현함 ㅋㅋㅋㅋㅋㅋ 개웃겨 아니 안웃겨.

처음에 문제를 아기 상어들 사이의 최대 거리를 구하는 줄 알고,,,  아기상어 위치를 다 저장해서 2개를 조합으로 뽑아서 각 뽑힌 조합의 최대 거리를 구해서 갱신하는 방식으로 했다...

알고 보니 ^^,, 각 빈칸에서 가장 가까운 상어와의 거리..를 구하는....문제였다.

거리를 구하는것이기 때문에 당연히 BFS 탐색을 사용했고, 가장 가까운 상어와의 안전거리라서 탐색하다 상어를 마주치면 바로 그 전 까지의 거리를 리턴해주는 형식으로 구현했따.

 

1. map을 입력받으면서 빈칸의 위치를 따로 다 저장해둠 (모든 빈칸에 대해서 상어와의 안전거리를 비교해야하기 때문이다)

2. BFS 탐색을 진행하며 8방향으로 이동하고 거리를 누적해나간다.

3. 만약 상어와 마주친다면 그 전까지의 이동 거리를 리턴해준다.

4. 모든 빈칸에 대해 2,3연산을 진행한 후 최대 안전거리를 갱신하며 출력해준다.

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>

using namespace std;

int n,m;
int map[55][55],ch[55][55];
int dx[8]={-1,-1,-1,0,1,1,1,0};
int dy[8]={-1,0,1,1,1,0,-1,-1};
vector<pair<int,int> > vec;
int ans = -214700000;
struct State{
    int x,y,cnt;
    State(int a, int b, int c){
        x = a;
        y = b;
        cnt = c;
    }
};

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

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

        if(map[x][y]) return cnt;

        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(ch[nx][ny]) continue;
            ch[nx][ny] = 1;
            que.push(State(nx,ny,cnt+1));
        }
    }    
}

int main(void){
    cin>>n>>m;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            cin>>map[i][j];
            if(!map[i][j]) vec.push_back(make_pair(i,j));
        }
    }

    for(int i=0; i<vec.size(); i++){
        int x = vec[i].first;
        int y = vec[i].second;
        ans = max(ans,BFS(x,y));
    }
    cout<<ans<<"\n";

}

요즘 왜이리 자료구조 문제를 푸냐 -> 담주 코테라서 .. 복습겸 ^^.... 개 싫다....고...요....

 

- 14425번 문자열 집합 

 

14425번: 문자열 집합

첫째 줄에 문자열의 개수 N과 M (1 ≤ N ≤ 10,000, 1 ≤ M ≤ 10,000)이 주어진다.  다음 N개의 줄에는 집합 S에 포함되어 있는 문자열들이 주어진다. 다음 M개의 줄에는 검사해야 하는 문자열들이 주어

www.acmicpc.net

<풀이>

집합 내에 존재하는 문자열의 개수를 세어주면 된다

나는 중복을 걸러주는 자료구조 set을 사용했다

집합 S내에 속해있는 문자열을 set에 넣어주고, M개만큼 새로운 문자열이 입력되었을 때, 같은 문자열이 set내에 1개 이상이라면 문자열 집합내에 존재한다고 개수를 세어준다 ~ 이런 문제만 코테에 나오면 안될까요...제발요...

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <set>

using namespace std;

int n,m;
int main(void){
    cin>>n>>m;
    string str;
    set<string> st;

    for(int i=0; i<n; i++){
        cin>>str;
        st.insert(str);
    }   
    int cnt = 0;
    for(int i=0; i<m; i++){
        cin>>str;
        if(st.count(str)>0) cnt++;
    }

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

 

- 2075번 N번째 큰 수 

 

2075번: N번째 큰 수

첫째 줄에 N(1 ≤ N ≤ 1,500)이 주어진다. 다음 N개의 줄에는 각 줄마다 N개의 수가 주어진다. 표에 적힌 수는 -10억보다 크거나 같고, 10억보다 작거나 같은 정수이다.

www.acmicpc.net

<풀이>

너무 쉽게 생각해서 그런지  1차는 메모리초과. 2차는 시간초과의 어택을 받았다.. 

 

첫 접근은 그냥 우선순위 큐를 사용해 최대 힙으로 배열을 모두 입력받고, n번째의 최댓값이기 때문에 n-1개의 요소를 빼주고 나서의 큐의 top 출력으로 했더니 메모리 초과가 나왔다.

 

두 번째 접근은 우선순위 큐를 주어진 n번째의 수에 맞게 사이즈를 n으로 생각하고 풀었다.

첫 번째 접근과 다르게 최소 힙으로 하여 큐의 구조를 활용했다.

n =5라면 큐의 사이즈가 5라고 생각을 하여, 최소 힙이기 때문에 top에는 항상 제일 작은 값이온다.

즉 큐의 사이즈가 5라면 그때부터 top과 들어오는 값을 비교하여  값이 크면 top을 빼고, 새로운 값을 넣어주며 최댓값만이 들어가게 갱신해준다. 만약 큐의 사이즈가 n보다 작다면 일단 큐에 숫자를 넣어준다.

 

즉, 모든 배열 요소를 다 넣어서 정렬했던 첫 번째 접근과 달리 두 번째 접근은 n개의 수만 정렬하는식으로 구현했다.

그런데도 시간초과가 난 이유는,,, cin/cout의 입출력 속도.. 때문으로 빠르게 해주는 구문을 추가해서 해결했다

예전에는 scanf, printf 정말 많이 썼는데 뭔가 cin/cout쓰고 나서 너무 편해서 못 돌아가겠음.. ㅋㅋㅋㅋㅋ

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <queue>

using namespace std;


int n;

int main(void){
    ios_base :: sync_with_stdio(false); 
    cin.tie(NULL); 
    cout.tie(NULL);
    cin>>n;
    int num;
    priority_queue<long long, vector<long long> , greater<long long> > que;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            cin>>num;
           if(que.size()==n){
               if(num>que.top()){
                   que.pop();
                   que.push(num);
               }
           }
           else que.push(num);
        }
    }
    
    cout<<que.top()<<"\n";
   
}

 

 

- 10546번 배부른 마라토너

 

10546번: 배부른 마라토너

마라토너라면 국적과 나이를 불문하고 누구나 참가하고 싶어하는 백준 마라톤 대회가 열린다. 42.195km를 달리는 이 마라톤은 모두가 참가하고 싶어했던 만큼 매년 모두가 완주해왔다. 단, 한 명

www.acmicpc.net

<풀이>

혹시나 하는 마음에 vector<pair<string, int> > 로 풀었다가 시간초과 폭탄 맞음 ㅋㅋ...아오 ㅋㅋ..

map으로 재도전 했다. 여기서 포인트는 동명이인이 있을 수 있다는 점이다!!

n번 참가자의 이름을 map으로 받으면서 카운팅을 해주고, n-1개의 도착한 사람의 이름을 받으며 값을 줄여준다.

만약 동명이인이나 들어오지 못한경우에는  해당 이름의  map내의 값이 홀수이기 때문에, 이걸 기준으로 못들어 온 한 명을 걸러줬다.

 

1. map으로 마라토너 참가자 이름의 개수를 세어줌

2. 못들어온 마라토너를 찾기 위해서 벡터에 따로 이름을 넣어준다. -> map의 경우에는 key값으로만 value를 찾을 수 있기 때문에

3. n-1 번 만큼 도착한 마라토너의 값을 줄어줌

4. 벡터에 저장된 마라토너의 이름 만큼 for 문을 돌면서 도착하지 못한 마라토너를 찾아준다.

 

4번에서  문제를 제대로 안보고 도착 못한 사람이 여러명 있을 수 있다 생각하여  종료 조건을 안넣었더니 30%대에서 또 틀림 ㅋㅋ 아 ㅋㅋ..  조건에는 1명만이 못들어왔다고 써 있으니.. 그 부분에 대해서 출력 후 종료를 넣으니 통과 !

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;

int n;

int main(void){
    ios_base :: sync_with_stdio(false); 
    cin.tie(NULL); 
    cout.tie(NULL);
    cin>>n;
    vector<string> vec;
    map<string,int> mp;
    
    string st;
    for(int i=0; i<n; i++){
        cin>>st;
        mp[st]++;
        vec.push_back(st);
    }

    for(int i=1; i<n; i++){
        cin>>st;
        mp[st]--;
    }

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


}

 

- 1269번 대칭 차집합

 

1269번: 대칭 차집합

첫째 줄에 집합 A의 원소의 개수와 집합 B의 원소의 개수가 빈 칸을 사이에 두고 주어진다. 둘째 줄에는 집합 A의 모든 원소가, 셋째 줄에는 집합 B의 모든 원소가 빈 칸을 사이에 두고 각각 주어

www.acmicpc.net

<풀이>

이 문제는 set을 사용했다.  집합 a에 대한 값을 set에 넣고, 집합 b에 대한 원소를 넣을 때, 이미 a에 있는 (set에 존재하여 count>=1) 경우 그 요소를 빼주고, 없으면 넣어주는 식으로 중복을 제거해주면서 set을 유지시키도록 구현했다.

은근 set이나 map 사용하는게 낯설어서 구현 과정에 생각을 좀 했어야 했다..

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

int n,m,tmp;
int main(void){
    ios_base :: sync_with_stdio(false); 
    cin.tie(NULL); 
    cout.tie(NULL);

    cin>>n>>m;
    set<int> st;

    for(int i=0; i<n; i++){
        cin>>tmp;
        st.insert(tmp);
    }

    for(int j=0; j<m; j++){
        cin>>tmp;

        if(st.count(tmp)) st.erase(tmp);
        else st.insert(tmp);
    }

    cout<<st.size()<<"\n";
}

 

머했다고,, 벌써 38일차가 됐는지,,

 

- 3986번 좋은단어

 

3986번: 좋은 단어

이번 계절학기에 심리학 개론을 수강 중인 평석이는 오늘 자정까지 보고서를 제출해야 한다. 보고서 작성이 너무 지루했던 평석이는 노트북에 엎드려서 꾸벅꾸벅 졸다가 제출 마감 1시간 전에

www.acmicpc.net

<풀이>

자료구조를 다 까먹은거 같아서 오랜만에 스택문제를 풀었다.

같은 글자와 짝 지을 수 있다면 좋은 단어 라는 부분에서  스택을 활용해 스택의 top의 단어와 입력될 단어가 같으면 pop해주는 식으로 사용했다.

단어 수가 주어지고, 그 만큼 입력이 되기 때문에 입력되는 문자를 매개변수로 하는 체크용 함수를 따로 만들었다.

좋은 단어라면 리턴을 true로 아니면 false로 하는 방식으로 구현했다.

뭔가 문자 +  스택 관련 문제가 많은거 같다. 가물가물하지만 상반기 국은 코테에서도 이런 스타일 문제가 있었던거 같은데.. 기억이 잘 안나네..

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stack>

using namespace std;


int n;
bool check(string str){
    stack<char> st;

    for(int i=0; i<str.size(); i++){
        if(st.empty()) st.push(str[i]);
        else if(!st.empty() && st.top() == str[i]){
            st.pop();
        }
        else{
            st.push(str[i]);
        }
    }
    if(st.empty()) return true;
    else return false;
}

int main(void){
    cin>>n;
    int cnt =0;
    string s;
    while(n--){
        cin>>s;
        if(check(s)) cnt++;
    }

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

 

 

-2346번 풍선 터뜨리기

 

2346번: 풍선 터뜨리기

1번부터 N번까지 N개의 풍선이 원형으로 놓여 있고. i번 풍선의 오른쪽에는 i+1번 풍선이 있고, 왼쪽에는 i-1번 풍선이 있다. 단, 1번 풍선의 왼쪽에 N번 풍선이 있고, N번 풍선의 오른쪽에 1번 풍선

www.acmicpc.net

<풀이>

deque를 활용한 문제 !

원형큐 처럼 구현했다  

풍선을 터뜨릴 때의 인덱스 값이 양수라면 앞 요소를 뒤로 넣어주고, 인덱스 값이 음수라면  뒤 요소를 앞으로 땡겨주며 회전시켜준다.

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <deque>
using namespace std;


int n;
int main(void){
    cin>>n;
    deque<pair<int,int> > que; 
   

    for(int i=1; i<=n; i++){
        int a;
        cin>>a;
        que.push_back(make_pair(i,a));    
    }

   while(!que.empty()){
       if(que.size() == 1){
           cout<<que.front().first<<"\n";
           return 0;
       }

       int num = que.front().second;
       cout<<que.front().first<<" ";
       que.pop_front();
       if(num>0){
           for(int i=0; i<num-1; i++){
               int nidx = que.front().first;
               int nnum = que.front().second;
               que.pop_front();
               que.push_back(make_pair(nidx,nnum));
           }
       }
       else{
           num = num*-1;
           for(int i=0; i<num; i++){
               int nidx = que.back().first;
               int nnum = que.back().second;
               que.pop_back();
               que.push_front(make_pair(nidx,nnum));
           }
       }
   }
}

 

-1935번 후위 표기식2

 

1935번: 후위 표기식2

첫째 줄에 피연산자의 개수(1 ≤ N ≤ 26) 가 주어진다. 그리고 둘째 줄에는 후위 표기식이 주어진다. (여기서 피연산자는 A~Z의 영대문자이며, A부터 순서대로 N개의 영대문자만이 사용되며, 길이

www.acmicpc.net

<풀이>

스택을 활용!

 후위 표기식이 주어 질 때, 후위 표기식 같은경우엔 연산자가 나오면 앞 피연산자를 꺼내와서 연산을 진행해주면 된다.

이 때 스택의 경우 LIFO구조이기 때문에 top의 연산자 위치가 바껴서 들어감을 기억해야한다.

이부분을 신나게 놓쳐서 왜 자꾸 연산 값이 마이너스가 나오나 ...했다....

ab-라면  a-b연산이 진행되어야한다. 하지만 스택에는 연산자가 아닌 피연산자가 들어간다.

a / b (top)부분이라면  먼저 꺼내오는 피연산자가 b가된다. 고로 b를 꺼내고 a를 꺼내오는 방식이라 연산을 진행할 때 이부분을 꼭 생각해야한다!!!

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <stack>

using namespace std;


int n;
int arr[26];

int main(void){
    cin>>n;
    string str;
    cin>>str;

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

    stack<double> st;

    for(int i=0; i<str.size(); i++){
        if(str[i]=='+'){
            double n1 = st.top();
            st.pop();
            double n2 = st.top();
            st.pop();

            st.push(n1+n2);
        }
        else if(str[i]=='*'){
            double n1 = st.top();
            st.pop();
            double n2 = st.top();
            st.pop();

            st.push(n1*n2);
        }
        else if(str[i]=='/'){
            double n1 = st.top();
            st.pop();
            double n2 = st.top();
            st.pop();

            st.push(n2/n1);
        }
        else if(str[i]=='-'){
            double n1 = st.top();
            st.pop();
            double n2 = st.top();
            st.pop();

            st.push(n2-n1);
        }
        else{
            int idx = str[i]-'A';
            st.push(arr[idx]);
        }
    }
    printf("%0.2f", st.top());
}

 

- 17265번 나의 인생에는 수학과 함께

 

17265번: 나의 인생에는 수학과 함께

세현이의 인생의 목표는 1분 1초 모든 순간 수학과 함께 살아가는 것이다. 그렇기 때문에 매일 수학을 생각하면서 살아가고 있다. 세현이는 밥을 먹을 때도 쌀알의 수를 계산하여 칼로리를 바로

www.acmicpc.net

<풀이>

제목은 절대 이해할 수 없지만 문제는 나름 재밌었다.

다른 문제와 달리 탐색을 할 때 오른쪽, 아래  두 방향만 이동가능하다는 점을 고려해주면 된다.

DFS를 사용하여 도착지점에 도달했을 때의 최소, 최대 값을 갱신해준다.

 

탐색의 경우에는 그 전이 숫자라면 다음이 무조건 연산기호 이렇게 나오기 때문에 이부분을 생각해주었다.

만일 다음 이동하는 곳이 방문하지 않았으며, 현 위치가 연산기호라면  다음 이동할 지점은 숫자가 된다.

현 위치의 연산 기호를 활용해 새로운 값으로 연산을 진행하고, 그 것을 바탕으로 DFS 탐색을 진행한다. 

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <cstring>

using namespace std;
int maxAns = -214700000;
int minAns = 214700000;

int n;
char map[10][10];
int ch[10][10];
int dx[2]={0,1};
int dy[2]={1,0};

void DFS(int x, int y, int sum){
    if(x==n-1 && y==n-1){
        maxAns = max(maxAns,sum);
        minAns = min(minAns,sum);
        return;
    }
    else{
        for(int i=0; i<2; 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]){
                ch[nx][ny] = 1;
                if(map[x][y]=='+') DFS(nx,ny,sum+(map[nx][ny]-'0'));
                else if(map[x][y]=='-') DFS(nx,ny,sum-(map[nx][ny]-'0'));
                else if(map[x][y]=='*') DFS(nx,ny,sum*(map[nx][ny]-'0'));
                else DFS(nx,ny,sum);

                ch[nx][ny] = 0;
            }
        }
    }
}

int main(void){
    cin>>n;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            cin>>map[i][j];
        }
    }
    DFS(0,0,map[0][0]-'0');
    cout<<maxAns<<" "<<minAns<<"\n";

}

 

-19699번 소-난다!

 

19699번: 소-난다!

지난 번 헛간 청약의 당첨우(牛)가 발표됐다. 청약에 당첨된 소들은 날아갈 듯이 기뻐하다가 진짜로 하늘을 날았다. 하지만 이후로 소들은 날 수 없었다. 그러던 어느 날, 꿀벌에게 쏘이면 잠깐

www.acmicpc.net

<풀이>

백트래킹 문제풀기 ~

1. 에라토스테네스의 체를 사용하여 소수를 미리 판별하기

2. 백트래킹을 사용하여 m개의 소를 선별해서, 선별한 소의 합을 1번에서 구한 소수 판별 배열로 체크해준다.

이때 소의 합이 소수라면 벡터에 따로 보관

3. 예외 처리를 위해 벡터가 비어있으면 (=그러한 경우 없는상황) -1 출력  벡터가 비어있지 않다면 값을 정렬하고, 중복된 값이 있을 수 있기 때문에 unique와 erase 함수를 사용하여 중복 요소를 삭제해준다. 

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;
int n,m;
int cow[11], ch[11],d[10001];
vector<int> vec;

void DFS(int L, int s){
    if(L==m){
        int sum =0;
        for(int i=0; i<m; i++){
            sum+=cow[ch[i]];
        }
        if(d[sum]) vec.push_back(sum);
        return;
    }
    else{
        for(int i=s; i<n; i++){
            ch[L] = i;
            DFS(L+1, i+1);
            ch[L] = 0;
        }
    }
}

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

    //소수 판별 용 
    for(int i=2; i<10001; i++){
        d[i] = 1;
    }

    for(int i=2; i*i<10001; i++){
        for(int j= i*i; j<10001; j+=i){
            if(d[j]==0) continue;
            else d[j] = 0;
        }
    }
    DFS(0,0);
    if(vec.empty()) cout<<-1<<"\n";
    else{
        sort(vec.begin(),vec.end());
        vec.erase(unique(vec.begin(),vec.end()),vec.end());
        for(int i=0; i<vec.size(); i++){
            cout<<vec[i]<<" ";
        }
    }
    cout<<"\n";
}

 

 

- 1620번 나는야 포켓몬 마스터 이다솜

 

1620번: 나는야 포켓몬 마스터 이다솜

첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면

www.acmicpc.net

<풀이>

첫 접근은 vector를 사용해 pair <string, int> 로 처리했더니 16%쯤에서 시간초과 

두 번째 접근은 map을 사용했다.

map은 <key, value >구조 이기 때문에  숫자가 입력됐을 때의 포켓몬 이름 출력을 위해 따로 string배열을 하나 두었다.

입력되는 문자열의 값이 숫자라면 이름 출력을 위해 생성한 string배열에서 뽑고 , 아니라면 바로 map의  key-value특성에 따라 출력해주면 된다.

 

 

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <map>


using namespace std;

int n,m;
map<string,int> mp;
string name[100001];
int main(void){
    cin.tie(0);
    cin>>n>>m;
    string str;
    for(int i=1; i<=n; i++){
        cin>>str;
        mp.insert(make_pair(str,i));
        name[i] = str;
    }
    char ch[21];
    for(int i=0; i<m; i++){
        cin>>ch;

        if(ch[0]>='0' && ch[0]<='9'){
            cout<<name[atoi(ch)]<<"\n";
        }
        else{
            cout<<mp[(string)ch]<<"\n";
        }
    }
}

- 1915번 가장 큰 정사각형

 

1915번: 가장 큰 정사각형

첫째 줄에 n, m(1 ≤ n, m ≤ 1,000)이 주어진다. 다음 n개의 줄에는 m개의 숫자로 배열이 주어진다.

www.acmicpc.net

<풀이>

DP문제 

해당 점 기준으로 왼쪽, 왼쪽 위, 위쪽 중에 최솟 값 + 1 이 만들 수 있는 가장 큰 정사각형의 변의 길이라는 걸 생각해서 식을 세우면 된다.

넘 어려워 dp는 

#include <iostream>
#include <stdio.h>
#include <algorithm>


using namespace std;

int map[1001][1001];

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

    
    int ans = 0;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++){
            
            if(map[i][j]){
                map[i][j] = min(min(map[i-1][j-1],map[i-1][j]),map[i][j-1])+1;
            }
            ans = max(ans, map[i][j]);
        }
    }

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

 

- 14925번 목장 건설하기 

 

14925번: 목장 건설하기

랜드 씨는 퇴직금으로 땅을 사서 목장을 지으려 한다.  그가 사려고 소개받은 땅은 직사각형이고 대부분 들판이지만, 여기저기에 베기 어려운 나무와 치울 수 없는 바위가 있다. 그는 목장을 하

www.acmicpc.net

<풀이>

위에 문제와 접근법이 아주 유사한 DP문제다 

위에 문제와 달리 이 문제는 나무와 돌이 없어야 하고 들판만 있는 상태에서의 만들 수 있는 정사각형의 한 변의 크기를 구해야한다.

그렇기 때문에 map을 바로 가져다 쓰지 않고 따로 dp배열을두어 행렬의 원소가 0일 때만 생길 수 있는 정사각형의 한 변의 크기를 갱신했다

 

이번에 문제 풀면서 알게 된 점.... 만들 수 있는 정사각형의 크기를 구하려면  해당 좌표 에서 왼쪽/ 왼쪽위/ 위  중에 최솟값 + 1이 해당 지점에서 만들 수 있는 최대 크기의 정사각형 이라는 것...이다.... 신기하네...요

시뮬이랑 완탐이 너무 약해서 관련 문제도 풀어야하는데....개싫다....정말루.....탐주 코테 대비 sql도 해야하는데....정말...싫다....

#include <iostream>
#include <stdio.h>
#include <algorithm>


using namespace std;

int n,m;
int map[1001][1001];
int dp[1001][1001];
int main(void){
    cin>>m>>n;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            cin>>map[i][j];
        }
    }
    int ans = 0;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            if(map[i][j]==0){
                dp[i][j] = min(min(dp[i-1][j-1], dp[i-1][j]),dp[i][j-1])+1;
                ans = max(ans, dp[i][j]);
            }
        }
    }

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

 

 

- 15711번 환상의 짝꿍

 

15711번: 환상의 짝꿍

환상의 나라 디디랜드에서는 인연의 증표로 끈을 하나씩 가지고 있다. 그들은 지극히 평범한 방법으로 이 끈을 이용하여 어떤 두 사람이 환상의 짝꿍인지 판단하는데, 두 사람의 끈을 서로 이

www.acmicpc.net

<풀이>

너무 쉽다고 생각하고 도전해서 그런지 놓친부분이 너무 많았다.... 5번이나 틀림 ㅠㅠ

 

사용한 알고리즘? 개념?은

1. 소수를 구하기 - 에라토스테네스의 체 

2. 골드바흐의 추측 - 2보다 큰 짝수는 두개의 소수의 합으로 표시할 수 있다 

 

이와 같다.

 

처음 접근은 에라토스테네스의 체로 범위 2 ~ 2000001 까지의 소수를 구해주었다.

그 후 입력되는 a,b의 값의 범위를 확인해 long long type으로 선언하여 두 합이 소수로 표현가능한지 단순 이중 포문으로 체크를 했는데

너무 당연하게도......타입까지 생각했으면 무조건 터지는거 알았을 텐데..뭔생각으로 했는지  당연히 터졌다 ...

 

두 번째 접근은 골드바흐의 추측법을 사용했다.  

크게 3가지로 나눴다.

1. 합이 4미만일 때 -> 무조건 소수의 합으로 표현 못함  

2. 합이 4이상의 짝수 일때 -> 골드바흐의 추측 개념에 부합함

3. 합이 1과2를 만족하지 않고 홀수 일때 (홀수 = 짝수 + 홀수 형태여야만 한다. 소수에서 짝수는 2밖에 없음!!)  

3번 부분에서 2가지를 생각해주어야하는데  하나를 놓쳐서 계속 틀렸다. 3번에서 고려해야할 부분은

3-1.  합-2 (=홀수) 이  에라토스테네스의 체로 걸러주었던 범위보다 작을 때 => 바로 소수인지 판별 (미리 구한 소수배열로)

3-2. 합-2가 에라토스테네스의 체로 걸러둔 범위보다 넘을 때 !!!!! 이 부분을 생각도 못했다....뭐지 나.........

열심히 구글링 한 결과   소수들로 나누어 떨어지지 않으면 소수이다 라는 개념을 사용했다.

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>


using namespace std;

int d[2000001];
vector<int> vec;


int main(void){
    int t;
    cin>>t;

    for(int i=2; i<2000001; i++){
        d[i] = 1;
    }

    for(int i=2; i*i<2000001; i++){
        for(int j=i*i; j<2000001; j+=i){
            if(d[j]==0) continue;
            else d[j] = 0;
        }
    }

    for(int i=2; i<2000001; i++){
        if(d[i]) vec.push_back(i);
    }


    while(t--){
        long long a,b;
        cin>>a>>b;
        long long sum = a+b;
        if(sum<4) cout<<"NO"<<"\n";
        else if(sum%2 ==0 ) cout<<"YES"<<"\n";
        else{
            sum-=2;
            if(sum<2000001){
                if(d[sum]) cout<<"YES"<<"\n";
                else cout<<"NO"<<"\n";
            }
            else{
                bool check = true;
                for(int i=0; i<vec.size(); i++){
                    if(sum%vec[i]==0){
                        check = false; 
                        break;
                    }
                }
                if(check) cout<<"YES"<<"\n";
                else cout<<"NO"<<"\n";
           }
        }
       
    }
}

 

 

 

- 2174번 로봇 시뮬레이션

 

2174번: 로봇 시뮬레이션

첫째 줄에 두 정수 A, B가 주어진다. 다음 줄에는 두 정수 N, M이 주어진다. 다음 N개의 줄에는 각 로봇의 초기 위치(x, y좌표 순) 및 방향이 주어진다. 다음 M개의 줄에는 각 명령이 명령을 내리는 순

www.acmicpc.net

<풀이>

와 진짜 저번주인가 부터 도전했는데 계에에에속 3%에서 한 10번넘게 틀려서 포기햇던 문제였다.

오늘 조금 여유가 생겨서 다시 처음부터 싹 고쳤다.... 하 겨우 맞았네ㅠㅠ

구글링 겁나해서 로직도 다 비교했는데 도대체가 오류를 못찾았었다.

이제 보니...원인은...결국...입력 받아올때 부분이었다...ㅅㅂ.......열받아...

내가 놓친부분은 다음과 같다.

 

1. a,b 입력 순서와 n개의 로봇 위치가 입력될 때 x,y좌표 입력 순서가 바뀐거 !!!!!

그리고 해당 배열의 좌표가 일반적인  좌표와 다르다  행부분의 좌표가 거꾸로 되어 있어서 이부분에 대한 처리가 1단계 더 필요했다.

 

2. 그 외에는 각 입력되는 명령어 마다  명령어 처리 횟수만큼 처리해주고 , 변화된 로봇의 값을 갱신해주면 된다.

 

 

진짜 1번때문에 몇번을 틀린건지... 내 백준 정답비율 돌려줘요....

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>


using namespace std;
int dx[4]={-1,0,1,0};
int dy[4] ={0,1,0,-1};
int lDir[4]={3,0,1,2};
int rDir[4]={1,2,3,0};

int map[101][101];
int robots[101][3];
int a,b,n,m;

bool move(int num, char cmd, int cnt){
    int x = robots[num][0];
    int y = robots[num][1];
    int dir = robots[num][2];

    map[x][y] = 0;

    while(cnt--){

        if(cmd == 'L'){
            dir = lDir[dir];
        }
        else if(cmd == 'R'){
            dir = rDir[dir];
        }
        else if(cmd == 'F'){
            x = x + dx[dir];
            y = y + dy[dir];

            if(x<1 || x>a || y<1 || y>b){
                printf("Robot %d crashes into the wall\n",num);
                return true;
            }

            if(map[x][y]){
                printf("Robot %d crashes into robot %d\n",num,map[x][y]);
                return true;
            }
        }
    }

    map[x][y] = num;
    robots[num][0] = x;
    robots[num][1] = y;
    robots[num][2] = dir;

    return false; 

}

int main(void){
    cin>>b>>a;
    cin>>n>>m;
    int x,y;
    char dir;
    for(int i=1; i<=n; i++){
        cin>>y>>x>>dir;
        int d = 0;
        if(dir == 'N') d=0;
        else if(dir == 'E') d=1;
        else if(dir=='S') d=2;
        else d=3;

        int posx = (a+1)-x;

        robots[i][0] = posx;
        robots[i][1] = y;
        robots[i][2] = d;

        map[posx][y] = i;
    }

    int num,cnt;
    char cmd;
    bool check = false;
    for(int i=1; i<=m; i++){
        cin>>num>>cmd>>cnt;

        if(!check){
            check = move(num,cmd,cnt);
        }
    }

    if(!check) cout<<"OK"<<"\n";
}

 

+ Recent posts