2018년 9월 29일 토요일

15949 Piet

15949 Piet https://www.acmicpc.net/problem/15949

Piet은 프로그래밍의 언어의 한 종류로 2차원 이미지로 구성이 되있다.
지문에서 설명되있는 그대로를 구현하면 되는 문제다.
같은 색깔 블록의 좌표 정보를 전처리로 구해놓고 유효한 코델이 나올 때 까지 찾아주었다.
현재 블록의 코델들 중 DPCC에 해당하는 값은 정렬시켜서 찾아주었다.
DPCC로 블록이 이동하는데 CCDP의 상대적인 값에 유의 하자!

2018 UCPC 본선 문제였는데 시간이 얼마 남지 않았을 때 봐서 풀지 못했던 문제다 ㅠㅠ
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
int n, m;
char arr[MAXN][MAXN];
int num[MAXN][MAXN];
int dy[] = { -1,0,1,0 };
int dx[] = { 0,1,0,-1 };
// up ,right, down, left
enum dir{
    up = 0, right, down, left 
};
struct Info {
    int y, x;
    int dp, cc;
    Info() {}
    Info(int yy, int xx, int ddp, int ccc) :y(yy), x(xx), dp(ddp), cc(ccc) {}
};
struct Point {
    int y, x;
    Point() {}
    Point(int yy, int xx) :y(yy), x(xx) {}
};
 
 
vector<Point> point[100001];
bool isout(int y, int x) {
    if (y < 0 || y >= n || x < 0 || x >= m) return true;
    return false;
}
void dfs(Point p, int cnt) {
    point[cnt].push_back(p);
    for (int i = 0; i < 4; i++) {
        int ny = p.y + dy[i], nx = p.x + dx[i];
        if (isout(ny, nx) || num[ny][nx] != -1 || arr[p.y][p.x] != arr[ny][nx]) continue;
        num[ny][nx] = cnt;
        dfs(Point(ny, nx), cnt);
    }
}
int main() {
    memset(num, -1sizeof num);
    scanf("%d%d"&n, &m);
    for (int i = 0; i < n; i++scanf("%s"&arr[i]);
 
    int cnt = 0;
    for (int i = 0; i < n; i++for (int j = 0; j < m; j++) {
        if (arr[i][j] == 'X'continue;
        if (num[i][j] != -1continue;
        num[i][j] = ++cnt;
        dfs(Point(i,j), cnt);
 
    }
    Info info(00, dir::right, dir::left);
    printf("%c", arr[0][0]);
    while (1) {
        Info cpy = info;
        int g = num[info.y][info.x];
        bool flag = false;
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 2; j++) {
                if (cpy.dp == dir::up) {
                    if (cpy.cc == dir::left) {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.y == b.y) return a.x < b.x;
                            return a.y < b.y;
                        });
                    }
                    else {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.y == b.y) return a.x > b.x;
                            return a.y < b.y;
                        });
                    }
                }
                else if (cpy.dp == dir::down) {
                    if (cpy.cc == dir::left) {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.y == b.y) return a.x > b.x;
                            return a.y > b.y;
                        });
                    }
                    else {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.y == b.y) return a.x < b.x;
                            return a.y > b.y;
                        });
                    }
                }
                else if (cpy.dp == dir::right) {
                    if (cpy.cc == dir::left) {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.x == b.x) return a.y < b.y;
                            return a.x > b.x;
                        });
                    }
                    else {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.x == b.x) return a.y > b.y;
                            return a.x > b.x;
                        });
                    }
                }
                else if (cpy.dp == dir::left) {
                    if (cpy.cc == dir::left) {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.x == b.x) return a.y > b.y;
                            return a.x < b.x;
                        });
                    }
                    else {
                        sort(point[g].begin(), point[g].end(), [](Point &a, Point &b)->bool {
                            if (a.x == b.x) return a.y < b.y;
                            return a.x < b.x;
                        });
                    }
                }
                Point res = Point(point[g][0].y + dy[cpy.dp], point[g][0].x + dx[cpy.dp]);
                if (!isout(res.y, res.x) && arr[res.y][res.x] != 'X') {
                    printf("%c", arr[res.y][res.x]);
                    flag = true;
                    info.y = res.y, info.x = res.x;
                    info.dp = cpy.dp; info.cc = cpy.cc;
                    break;
                }
                if(!j) cpy.cc += 2; cpy.cc %= 4;
            }
            if (flag) break;
            cpy.dp += 1; cpy.dp %= 4;
        }
        if (!flag) break;
    }
        
    return 0;
}
cs

2018년 9월 16일 일요일

C++ 디자인패턴 (Command Pattern)

Command Pattern

요구사항, 요청사항을 객체로 캡슐화하여 다양한 종류를 넣을 수 있다. 
또한 작업취소(undo)기능도 가능하다.

클래스 다이어그램과 코드는 wiki에서 가져왔다.

#include <iostream>
#include <vector>
#include <string>
using namespace std;
class Command {
public:
    virtual void execute(void= 0;
    virtual ~Command(void) {};
};
class Ingredient : public Command {
public:
    Ingredient(string amount, string ingredient) {
        _ingredient = ingredient;
        _amount = amount;
    }
    void execute(void) {
        cout << " *Add " << _amount << " of " << _ingredient << endl;
    }
private:
    string _ingredient;
    string _amount;
};
class Step : public Command {
public:
    Step(string action, string time) {
        _action = action;
        _time = time;
    }
    void execute(void) {
        cout << " *" << _action << " for " << _time << endl;
    }
private:
    string _time;
    string _action;
};
class CmdStack {
public:
    void add(Command *c) {
        commands.push_back(c);
    }
    void createRecipe(void) {
        for (vector<Command*>::size_type x = 0; x<commands.size(); x++) {
            commands[x]->execute();
        }
    }
    void undo(void) {
        if (commands.size() >= 1) {
            commands.pop_back();
        }
        else {
            cout << "Can't undo" << endl;
        }
    }
private:
    vector<Command*> commands;
};
int main(void) {
    CmdStack list;
    //Create ingredients
    Ingredient first("2 tablespoons""vegetable oil");
    Ingredient second("3 cups""rice");
    Ingredient third("1 bottle""Ketchup");
    Ingredient fourth("4 ounces""peas");
    Ingredient fifth("1 teaspoon""soy sauce");
    //Create Step
    Step step("Stir-fry""3-4 minutes");
    //Create Recipe
    cout << "Recipe for simple Fried Rice" << endl;
    list.add(&first);
    list.add(&second);
    list.add(&step);
    list.add(&third);
    list.undo();
    list.add(&fourth);
    list.add(&fifth);
    list.createRecipe();
    cout << "Enjoy!" << endl;
    return 0;
}
cs

2018년 9월 7일 금요일

2285 우체국

2285 우체국 https://www.acmicpc.net/problem/2285

N개의 마을은 각각 $X_{i}$에 위치하고 $A_{i}$의 사람들이 살고 있다.
우체국을 하나 세울 때 각 사람들 까지의 거리가 최소가 되는 위치를 구하는 문제이다.

처음엔 삼진검색을 생각했으나 $O(N)$ 알고리즘이 떠올랐다.

이 문제에서 우체국은 N개의 마을 중 한 곳에 세워줘야 최적이다.
$a$와 $b$사이가 $d$인 두 마을만 있는 경우를 예시로 들어보겠다.

$a<=x<=b$인 $x$가 존재한다고 가정했을 때 우리가 구하고자하는 값은 $A(x-a) + B(b-x)$이다.
$(A-B)x-Aa+Bb$의 값을 최소화하는것이 우리의 목표인데 
$-Aa+Bb$는 상수이므로 $x$차수항만 생각해 본다면 
$A-B>0$인 경우에는 절대값을 낮춰야 하므로 $x=a$가 되어야하고
$A-B<0$인 경우에는 절대값을 키워야 하므로 $x=b$가 되어야 한다.
따라서 두 위치중 한 곳이 최적이다.
마을이 3개 이상인것도 확장시켜 생각해보면 증명이 가능하다.

현재 마을에 우체국을 세운다고 생각했을 때 마을 기준으로 오른쪽과 왼쪽에 있는 사람들의 수와 
거리를 잘 관리하면 해결할 수 있다.
__int128을 사용하여 통과하였다 ㅋㅋ;

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
int n;
pair<ll, ll> arr[MAXN];
using Integer128 = __int128;
std::ostream& operator<<(std::ostream& dest, const Integer128& value)
{
    Integer128 tmp = value < 0 ? -value : value;
    std::array<char128> buffer;
    auto d = buffer.begin();
    while (tmp != 0) {
        *d++ = "0123456789"[tmp % 10];
        tmp /= 10;
    }
    if (value < 0) {
        *d++ = '-';
    }
    std::ostream_iterator<char> out_it(dest);
    std::reverse_copy(buffer.begin(), d, out_it);
    return dest;
}
int main() {
    cin >> n;
    for (int i = 0; i < n; i++cin >> arr[i].first >> arr[i].second;
    sort(arr, arr + n);
 
    __int128 fr = arr[0].second, en = 0;
    __int128 dist = 0;
    for (int i = 0; i < n; i++) {
        if(i) en += (__int128)arr[i].second;
        dist += (__int128)(arr[i].first - arr[0].first) * arr[i].second;
    }
    __int128 mx = dist;
    __int128 ans = arr[0].first;
    __int128 prv = 0;
 
    for (int i = 1; i < n; i++) {
        dist -= (__int128)(arr[i].first - arr[i - 1].first) * en;
        dist += (__int128)(arr[i].first - arr[i - 1].first) * fr;
        en -= (__int128)arr[i].second;
        fr += (__int128)arr[i].second;
        if (mx > dist) {
            mx = dist;
            ans = arr[i].first;
        }
        else if (mx == dist) {
            if (ans > arr[i].first) ans = arr[i].first;
        }
    }
    cout << ans;
    return 0;
}
cs

사실 더 간단한 풀이가 있다.
사람 수의 절반정도의 위치한 마을이 답이된다.

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
typedef long long ll;
int n;
pair<intint> arr[MAXN];
int main() {
    scanf("%d"&n);
    ll sum = 0, s = 0;
    for (int i = 0; i < n; i++scanf("%d%d"&arr[i].first, &arr[i].second), sum += arr[i].second;
    sort(arr, arr + n);
    for (int i = 0; i < n; i++) {
        s += arr[i].second;
        if (s * 2ll >= sum) {
            printf("%d\n", arr[i].first);
            break;
        }
    }
    return 0;
}
cs

2018년 9월 4일 화요일

C++ 디자인패턴 (Strategy Pattern)

Strategy Pattern
클라이언트 객체에서 서로 교환가능한 구현(전략)들을 의존성 없이 변경 가능하도록 하는 패턴


#include <iostream>
using namespace std;
class Strategy {
    public:
        Strategy() {}
        ~Strategy() {}
        virtual void execute() = 0;
};
class A_strategy : public Strategy {
    protected:
        virtual void execute() {
            printf("A strategy!\n");
        }
};
class B_strategy : public Strategy {
    protected:
        virtual void execute() {
            printf("B strategy!\n");
        }
};
class Character {
    public:
        Character() {}
        ~Character() {}
        void ChangeStrategy(Strategy *s) {
            if (this->stg != nullptr) {
                delete this->stg;
            }
            this->stg = s;
        }
        void Perform() {
            if (this->stg == nullptr) {
                printf("no strategy!\n");
                return;
            }
            this->stg->execute();
        }
    private:
        Strategy *stg;
};
int main() {
    Character *ch = new Character();
    ch->Perform();

    ch->ChangeStrategy(new A_strategy());
    ch->Perform();
    ch->ChangeStrategy(new B_strategy());
    ch->Perform();
    return 0;
}
cs

ch객체에서 A라는 전략을 수행한 후 전략을 바꾸어 B라는 전략을 수행하고있다.

(18.11.26) - python 버전 추가

class Strategy:
    _name = None
    def action(self):
        pass
 
    """ sub class """
class FirstStrategy(Strategy):
    def __init__(self, name):
        self._name = name
    def action(self):
        print(self._name,' First algorithm start!')
        
    """ sub class """
class SecondStrategy(Strategy):
    def __init__(self, name):
        self._name = name
    def action(self):
        print(self._name,' Second algorithm start!')
 
class Unit:
    _strategy = Strategy()
    _name = None
    def __init__(self, name):
        self._name = name
 
    def ChangeStrategy(self, strg):
        self._strategy = strg
 
    def Show(self):
        print('my name is ',self._name)
        self._strategy.action()
        print()
 
jihoon = Unit('JiHoon')
 
jihoon.ChangeStrategy(FirstStrategy('fly'))
jihoon.Show()
 
jihoon.ChangeStrategy(SecondStrategy('kill'))
jihoon.Show()
cs






파이썬 버전도 기본 logic은 동일하다.