반응형

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

 

14868번: 문명

표준 입력으로 다음 정보가 주어진다. 첫 번째 줄에는 세계의 크기를 나타내는 정수 N(2 ≤ N ≤ 2,000)과 문명 발상지의 수 K(2 ≤ K ≤ 100,000)가 주어진다. 다음 K줄에는 한 줄에 하나씩 문명 발상지

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;

int n, k, area = 0;
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };
int arr[2001][2001];
int unf[100001];

int Find(int x) {
    if (unf[x] < 0) return x;
    
    return unf[x] = Find(unf[x]);
}

void merge(int x, int y) {
    x = Find(x);
    y = Find(y);
    if (x == y) return;
    unf[x] = y;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    memset(unf, -1, sizeof(unf));

    int t = 0;
    int comp;

    queue<pair<int, int> > Q;
    queue<int> region;
    cin >> n >> k;
    for (int i = 0; i < k; i++) {
        int a, b;
        cin >> a >> b;
        arr[a][b] = ++area;
        region.push(area);
        comp = arr[a][b];
        Q.push({ a,b });
    }


    int q = Q.size();
    for (int i = 0; i < q; i++) {
        int x = Q.front().first;
        int y = Q.front().second;
        Q.pop();

        for (int j = 0; j < 4; j++) {
            int nx = x + dx[j];
            int ny = y + dy[j];
            if (nx <= 0 || nx > n || ny <= 0 || ny > n) continue;
            if (arr[nx][ny] > 0) {
                merge(arr[x][y], arr[nx][ny]);
            }
        }
        Q.push({ x,y });
    }



    while (!region.empty() && Find(comp) == Find(region.front())) {
        region.pop();
    }
    if (region.empty()) {
        cout << t << '\n';
        return 0;
    }
  
    while (!Q.empty()) {
        int q = Q.size();
        for (int i = 0; i < q; i++) {
            int x = Q.front().first;
            int y = Q.front().second;
            Q.pop();

            for (int j = 0; j < 4; j++) {
                int nx = x + dx[j];
                int ny = y + dy[j];
                if (nx <= 0 || nx > n || ny <= 0 || ny > n) continue;

                if (arr[nx][ny] == 0) {
                    arr[nx][ny] = arr[x][y];
                    Q.push({ nx, ny });
                }
                else if (Find(arr[x][y]) != Find(arr[nx][ny])) {
                    merge(arr[x][y], arr[nx][ny]);
                }
            }
        }
        t++;

        //인접한 곳에 union 되지 않은 영역 있는지 체크 
        q = Q.size();
        for (int i = 0; i < q; i++) {
            int x = Q.front().first;
            int y = Q.front().second;
            Q.pop();

            for (int j = 0; j < 4; j++) {
                int nx = x + dx[j];
                int ny = y + dy[j];
                if (nx <= 0 || nx > n || ny <= 0 || ny > n) continue;
                if (arr[nx][ny] > 0) {
                    merge(arr[x][y], arr[nx][ny]);
                }
            }
            Q.push({ x,y });
        }

		while (!region.empty() && Find(comp) == Find(region.front())) {
            region.pop();
        }
        if (region.empty()) {
            cout << t << '\n';
            return 0;
        }

    }
    
    return 0;
}

백준 14868번 : 문명

반응형
반응형

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

 

1178번: 간선 추가

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (2 ≤ V ≤ 1,000, 1 ≤ E ≤ V×(V-1)/2) 정점에는 1부터 V까지 번호가 매겨져 있다고 생각한다. 이어서 E개의 줄에 걸쳐 간선을 이루는 두 점 a와 b

www.acmicpc.net

1. 문제설명

 

주어진 그래프를 오일러 회로 or 오일러 경로로 만드려면

 

몇개의 간선이 추가로 필요한지 구해야 하는 문제입니다.

 

 


2. 접근방법[알고리즘]

 

주어진 그래프에서

Union & Find 알고리즘을 이용해

서로 다른 컴포넌트면서 차수가 0이거나 홀수인 노드를 우선 연결해주고

그 이후에도 서로 다른 컴포넌트가 남아있다면

컴포넌트 개수가 1이 될 때까지 모두 연결해준뒤

 

 

한붓그리기가 가능한

오일러 회로나 오일러 경로가 되려면

차수가 홀수인 노드가 최대 2개여야 하므로

 

차수가 홀수인 노드의 개수를 센 다음에

간선을 몇개 더 이어줘야하는지 구하면 답을 구할 수 있습니다.

 

 

 


 

3.문제풀이코드 C++

#include <bits/stdc++.h>
using namespace std;

int v, e, area, ans;
int degree[1001];
int unf[1001];

int Find(int x) {
    if (x == unf[x]) return x;
    else {
        return unf[x] = Find(unf[x]);
    }
}

void Union(int a, int b) {
    a = Find(a);
    b = Find(b);
    if (a != b) unf[a] = b;
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> v >> e;

    for (int i = 1; i <= v; i++) {
        unf[i] = i;
    }


    for (int i = 0; i < e; i++) {
        int a, b;
        cin >> a >> b;

        degree[a]++;
        degree[b]++;
        Union(a, b);
    }

    //1. 서로 다른 컴포넌트이며 둘 다 차수가 홀 수거나 0이면 이어준다.
    for (int i = 1; i <= v; i++) {
        for (int j = i + 1; j <= v; j++) {
            if ((degree[i] % 2 == 1 || degree[i]==0) && 
                (degree[j] % 2 == 1||degree[j]==0) && 
                (Find(i) != Find(j))) {
                Union(i, j);
                degree[i]++;
                degree[j]++;
                ans++;
            }
        }
    }

    //2. 둘다 차수가 짝수여도 서로 다른 컴포넌트일 경우 서로 이어준다.
    for (int i = 1; i <= v; i++) {
        for (int j = i + 1; j <= v; j++) {
            if (Find(i) != Find(j)) {
                Union(i, j);
                degree[i]++;
                degree[j]++;
                ans++;
            }
        }
    }

    int odd = 0;
    for (int i = 1; i <= v; i++) {
        if (degree[i] % 2 == 1) {
            odd++;
        }
    }


    //3. 차수가 홀 수 인 게 2개이상인 경우 그만큼 연결해주어야한다.
    ans += (odd - 2 > 0) ? ((odd - 2) / 2) : 0;

    cout << ans << '\n';
   
    return 0;
}

백준 1178번 간선 추가

 

반응형
반응형

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

 

16168번: 퍼레이드

첫 번째 줄에 지점의 개수 V, 연결 구간의 개수 E가 주어진다. (1 ≤ V ≤ E ≤ 3000) 이후 E개의 줄에 걸쳐 각 연결 구간이 연결하는 두 지점의 번호 Va, Vb가 공백을 사이에 두고 주어진다. (1 ≤ Va,

www.acmicpc.net

 

 

1. 컴포넌트 수가 1개여야 한다.

 

2. 오일러 회로이거나 오일러 경로여야한다. (차수가 홀수인 노드가 2개거나 0개여야한다)

 

#include <bits/stdc++.h>
using namespace std;

struct Edge {
    int to, c;
    Edge* dual;
    Edge() : Edge(-1, 0) {};
    Edge(int to1, int c1) :to(to1), c(c1), dual(nullptr) {};
};


vector<Edge*> adj[3001];
int v,e,degree[3001];
int odd;
bool visited[3001];

int DFS(int x) {
    int res = 1;
    visited[x] = 1;
    for (Edge* e : adj[x]) {
        if (e->c > 0 && visited[e->to]==0) {
            e->c--;
            e->dual->c--;
            res += DFS(e->to);
        }
    }
    return res;
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> v >> e;
    for (int i = 0; i < e; i++) {
        int a,b;
        cin >> a >> b;
        Edge* e1 = new Edge(b, 1), *e2 = new Edge(a,1);
        e1->dual = e2;
        e2->dual = e1;

        adj[a].push_back(e1);
        adj[b].push_back(e2);

        degree[a]++;
        degree[b]++;
    }

    for (int i = 1; i <= v; i++) {
        if (degree[i] % 2 == 1) {
            odd++;
        }

        if (odd > 2) {
            cout << "NO";
            return 0;
        }
    }

    bool flag = false;

    for (int i = 1; i <= v; i++) {
        if (!visited[i]) {
            int res = DFS(i);
            if (res > 1) {
                if (flag) {
                    cout << "NO";
                    return 0;
                }
                else {
                    flag = true;
                }
            }
        }
    }

    cout << "YES";

    return 0;
}

 

반응형
반응형

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

 

1199번: 오일러 회로

첫 줄에는 정점의 수 N(1 ≤ N ≤ 1,000)이 주어진다. 그리고 다음 N개의 줄에 대해 인접행렬의 정보가 주어진다. i+1번째 줄에는 i번 정점에 대한 인접행렬이 주어진다. 두 정점 사이에 간선이 여러

www.acmicpc.net

 

1.문제 설명

https://m.blog.naver.com/kks227/220800097205

 

오일러 경로(Eulerian Path), 오일러 회로(Eulerian Circuit) (수정: 2019-08-20)

이번에 소개할 내용은 오일러 경로(Eulerian trail) 및 오일러 회로(Eulerian circuit)입니다. 위상수학,...

blog.naver.com

주어진 입력값을 바탕으로 오일러 회로인지 판별하고

 

오일러 회로의 경로를 출력하는 문제입니다.

 

위 블로그에 자세한 설명이 되어있습니다.

 

 


2.접근방법[알고리즘]

 

최근 재채점이 된 이후 위 블로그의 풀이가 시간초과가 납니다.

그래서 다른 방법으로 간선 정보를 구현해야합니다.

 

 

vector<int> adj[MAX];
vector<pair<int, int> > Edge;
int Edge_cnt[MAX * MAX];
int edge_num;

A, B 노드가 있을 때

노드 번호 (A,B)를 Edge 벡터에 저장하고

A와 B 를 이어주는 간선(A,B)에 번호(edge_num)를 주고 

A와 B의 간선의 개수를 저장하는 배열(Edge_cnt)을 만듭니다.

 

이를 이용해 DFS를 돌면서 경로를 출력해주면 됩니다.

 

 


 

3.문제풀이코드 C++

#include <bits/stdc++.h>
#define MAX 1001
using namespace std;

int n;
vector<int> adj[MAX];
vector<pair<int, int> > Edge;
int Edge_cnt[MAX * MAX];
int edge_num;

void DFS(int x) {
    while (adj[x].size()) {
        int e = adj[x].back();
        int u = Edge[e].first;
        int v = Edge[e].second;

        if (Edge_cnt[e]) {
            Edge_cnt[e]--;

            if (x == u) {
                DFS(v);
            }
            else {
                DFS(u);
            }
        }
        else adj[x].pop_back();
    }
    cout << x+1 << ' ';
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;

    for (int i = 0; i < n; i++) {
        int degree = 0;
        for (int j = 0; j < n; j++) {
            int val;
            cin >> val;

            if (i < j && val >0) {
                Edge.push_back({ i,j });
                Edge_cnt[edge_num] = val;

                adj[i].push_back(edge_num);
                adj[j].push_back(edge_num++);
            }
			degree += val;
        }
        if ((degree % 2) == 1) {
            cout << -1 << '\n';
            return 0;
        }
    }

    DFS(0);

    return 0;
}

백준 1199번 오일러 회로

반응형
반응형

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

 

18111번: 마인크래프트

팀 레드시프트는 대회 준비를 하다가 지루해져서 샌드박스 게임인 ‘마인크래프트’를 켰다. 마인크래프트는 1 × 1 × 1(세로, 가로, 높이) 크기의 블록들로 이루어진 3차원 세계에서 자유롭게

www.acmicpc.net

 

높이를 0부터 256까지 모두 확인해주어야 문제를 해결할 수 있다.

 

초기 배열의 값들을 기준으로 높이를 설정해 최소시간을 구했는데

 

초기 배열에 존재하지 않는 값이 최소시간의 땅의 높이가 될 수 있다.

 

#include <bits/stdc++.h>
using namespace std;

int n, m, b, arr[501][501];
int height=-1, cnt = INT_MAX;

void func(int x) {
    int test_b = b;
    int test_cnt = 0;
    int test[501][501];

    copy(&arr[0][0], &arr[0][0] + 501 * 501, &test[0][0]);

    //파내기 먼저 해줘서 b를 확보한다
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (test[i][j] > x) {
                test_cnt += 2 * (test[i][j] - x);
                test_b += (test[i][j] - x);
                if (test_cnt > cnt) return;
            }
        }
    }

    //쌓기
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (test[i][j] < x) {
                test_b -= (x - test[i][j]);
                if (test_b < 0) return;
				test_cnt += (x - test[i][j]);

				if (test_cnt > cnt) return;
            }
        }
    }


    if (cnt > test_cnt) {
        cnt = test_cnt;
        height = x;
    }
    else if (cnt == test_cnt) {
        if (x > height) height = x;
    }

}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m >> b;

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

    for (int i = 0; i <= 256; i++) {
        func(i);
    }

    cout << cnt << ' ' << height << '\n';

    return 0;
}

백준 18111번

 

반응형
반응형

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

 

1948번: 임계경로

첫째 줄에 도시의 개수 n(1 ≤ n ≤ 10,000)이 주어지고 둘째 줄에는 도로의 개수 m(1 ≤ m ≤ 100,000)이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 도로의 정보가 주어진다. 처음에는 도로의

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;

int n, m;

vector<pair<int,int> > adj[10001];
vector<pair<int, int> > rev_adj[10001];
int redegree[10001];
int rev_res[10001];

int degree[10001];
int res[10001];

bool vis[10001];

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n >> m;

    for (int i = 0; i < m; i++) {
        int a, b,c;
        cin >> a >> b >> c;

        adj[a].push_back({ b,c });
        rev_adj[b].push_back({ a,c });
        redegree[a]++;
        degree[b]++;
    }

    queue<int> Q;

    int s, e;
	cin >> s >> e;
    Q.push(s);

    while (!Q.empty()) {
        int x = Q.front();
        Q.pop();

        for (auto i : adj[x]) {
            int nx = i.first;
            int nd = i.second;
            res[nx] = max(res[nx], res[x] + nd);

            if (--degree[nx] == 0) {
                Q.push(nx);
            }
        }
    }

    int ans = res[e];
    cout << res[e] << '\n';


    Q.push(e);

    while (!Q.empty()) {
        int x = Q.front();
        Q.pop();

        for (auto i : rev_adj[x]) {
            int nx = i.first;
            int nd = i.second;
            rev_res[nx] = max(rev_res[nx], rev_res[x] + nd);

            if (--redegree[nx] == 0) {
                Q.push(nx);
            }
        }
    }

    set<pair<int, int> > Set;
    Q.push(s);
    vis[s] = 1;
    while (!Q.empty()) {
        int x = Q.front(); Q.pop();

        for (auto i : adj[x]) {
            int nx = i.first;
            int d = i.second;
            if ((res[nx] == res[x] + d) && (res[nx] + rev_res[nx] == ans)) {
                if (!vis[nx]) {
					Q.push(nx);
                    vis[nx] = 1;
                }
                Set.insert({ x,nx });
            }
        }
    }

    cout << Set.size() << '\n';


    return 0;
}

백준 1948번 임계경로

 

반응형
반응형

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

 

2848번: 알고스팟어

첫째 줄에 알고스팟어의 알파벳 순서를 출력한다. 만약, 올바른 순서가 없다면 "!"를, 가능한 순서가 한 개 이상이라면 "?"를 출력한다.

www.acmicpc.net

#include <bits/stdc++.h>
using namespace std;


int n;
vector<string> v;

bool adj[26][26];
int degree[26];
int ch[26];

bool flag = false;
bool flag2 = false;

void comp(string s1, string s2) {
    int a = s1.length();
    int b = s2.length();

    int c = min(a, b);

    bool same = true;
    for (int i = 0; i < c; i++) {
        if (s1[i] != s2[i]) {
            int aa = int(s1[i] - 'a');
            int bb = int(s2[i] - 'a');

            if (adj[aa][bb] == 0) {
				adj[aa][bb] = 1;
				degree[bb]++;
            }

            same = false;
			break;
        }
    }


    //abc
    //ab 예외 처리 

    if (same) {
        if (a > b) flag2 = true;
    }
}


int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        string s;
        cin >> s;
        v.push_back(s);

        for (int j = 0; j < s.length(); j++) {
            ch[s[j] - 'a'] = 1;
        }
    }

    for (int i = 0; i < 26; i++) {
        if (ch[i]) cnt++;
    }


    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            comp(v[i], v[j]);
        }
    }

    if (flag2) {
        cout << "!\n";
        return 0;
    }


    queue<int> Q;

	for (int i = 0; i < 26; i++) {
		if (ch[i] == 1 && degree[i] == 0) {
			Q.push(i);
		}
	}


    
    vector<int> ans;
    while (!Q.empty()) {
        if (Q.size() >= 2) {
            flag = true;
            break;
        }

        int x = Q.front();
        Q.pop();
        ans.push_back(x);

        for (int i = 0; i < 26; i++) {
			if (ch[i] == 1 && adj[x][i] == 1) {
				if (--degree[i] == 0) {
					Q.push(i);
				}
			}
		}
    }


    if (flag) {
        cout << "?\n";
    }
    else if (ans.size() != cnt) {
        cout << "!\n";
    }
    else {
        for (auto x: ans) {
            cout << (char)(x + 'a');
        }
        cout << '\n';

    }


    return 0;
}

백준 2848번 알고스팟어 C++

 

반응형
반응형

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

 

2056번: 작업

수행해야 할 작업 N개 (3 ≤ N ≤ 10000)가 있다. 각각의 작업마다 걸리는 시간(1 ≤ 시간 ≤ 100)이 정수로 주어진다. 몇몇 작업들 사이에는 선행 관계라는 게 있어서, 어떤 작업을 수행하기 위해

www.acmicpc.net

 

#include <bits/stdc++.h>
using namespace std;

int n;
int cost[10003];
vector<int> adj[10003];
int degree[10003];
int res[10003];
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> cost[i];

        int k;
        cin >> k;
        for (int j = 0; j < k; j++) {
            int pre;
            cin >> pre;
            adj[pre].push_back(i);
            degree[i]++;
        }
    }

    int ans = 0;
    queue<int> Q;
    for (int i = 1; i <= n; i++) {
        if (degree[i] == 0) {
            res[i] = cost[i];
            Q.push(i);
            ans = max(res[i], ans);
        }
    }

    while (!Q.empty()) {
        int x = Q.front();
        Q.pop();

        for (auto nx : adj[x]) {
            res[nx] = max(res[nx], res[x] + cost[nx]);
            ans = max(ans, res[nx]);
            if (--degree[nx] == 0) {
                Q.push(nx);
            }
        }
    }


    cout << ans << '\n';
   
    return 0;
}

 

백준 2056번 작업

반응형

+ Recent posts