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


요즘 나태해져서.. 다시 열심히 해야겠습니다 ㅎㅎ!!

DP문제입니다!


간단하게 생각하면 별로 안어려운 문제인 것 같습니다!


딱봐도..4인데... 어떻게 dp로 접근했냐하면


for문은 행우선으로 진행하면 됩니다. 행의 모든 열을 다 돌면 다음행!


그리고 중요한 것은 해당 배열의 위, 왼쪽, 그리고 왼쪽위 대각선 이 세방향을 검사했습니다.


내가 1이고 그 세 개중에 가장 작은 값(0은 제외) + 1이 결국 정사각형의 변의 길이입니다.


예제를 보면서 해결해보도록하죠!


4 4

0100

0111

1110

0010


dp테이블을 써보도록하겠습니다.

0100
0111
1120
0010

최대 변의 길이는 2겠지요!?!
그래서 정답은 2 * 2 = 4입니다!!!!!!!!!!!!!!

아래는 코드입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <cstdio>
#define MAX_SIZE 1000
#define INF 0x7fffffff
 
bool arr[MAX_SIZE][MAX_SIZE];
int dp[MAX_SIZE][MAX_SIZE];
 
int min(int a, int b) {
    return a > b ? b : a;
}
 
int max(int a, int b) {
    return a > b ? a : b;
}
 
int main() {
 
    int m, n;
    scanf("%d %d"&m, &n);
 
 
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            scanf("%1d"&arr[i][j]);
        }
    }
 
    int ret = 0;
    int dx[3= { 0-1-1 };
    int dy[3= { -10-1 };
 
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (!arr[i][j]) continue;
 
            int min_value = INF;
            for (int k = 0; k < 3; k++) {
                int nx = i + dx[k];
                int ny = j + dy[k];
 
                if (nx < 0 || ny < 0) {
                    min_value = 0;
                    break;
                }
                min_value = min(min_value, dp[nx][ny]);
            }
            if (!min_value) dp[i][j] = 1;
            else if (min_value != INF) dp[i][j] = min_value + 1;
 
            ret = max(dp[i][j], ret);
        }
    }
 
    printf("%d\n", ret * ret);
 
    return 0;
}
cs


'알고리즘 > 다이나믹 프로그래밍(DP)' 카테고리의 다른 글

[2698] 인접한 비트의 개수  (0) 2017.07.04
[1029] 그림 교환  (0) 2017.06.27
[2629] 양팔 저울  (0) 2017.04.25
[2133] 타일 채우기  (0) 2017.04.20
[1309] 동물원  (0) 2017.04.20

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


네트워크 플로우에서 최대 유량 문제입니다.

저도 처음 공부하기 때문에 다른 블로그를 참조하면서 공부했습니다.


필요한 변수 선언입니다.


1
2
3
4
5
    int n; //input으로 받는 edge 수
    vector<int> adj[MAX_SIZE]; // 인접
    int capacity[MAX_SIZE][MAX_SIZE] = { 0, }; // 용량
    int flow[MAX_SIZE][MAX_SIZE] = { 0, }; // 흐르는 양
    int prev[MAX_SIZE]; // 경로를 저장(현재 정점의 이전 정점이 무엇이었는지)
cs


입력 부분입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//입력
    scanf("%d"&n);
    getchar();
 
    for (int i = 0; i < n; i++) {
        char s, e;
        int c;
 
        scanf("%c %c %d"&s, &e, &c);
        getchar();
 
        s = ctoi(s), e = ctoi(e); //입력 받은 정점을 숫자로 변환
 
        //같은 간선이 여러개 들어오면 용량이 그만큼 늘어나면 됨
        capacity[s][e] += c;
 
        //정,역방향 간선 추가
        adj[s].push_back(e);
        adj[e].push_back(s);
    }
cs


15번째 줄의 += 부분이 잘이해가 안가실 수 있습니다.

capacity배열은 0으로 전부 초기화 되어있습니다.

입력에서 만약 A -> B 로 가는 edge를 여러개로 준다면

A->B로 가는 유량은 edge의 총 용량만큼이기 때문에 +=로 해주는 것입니다.


19번째에서 역방향 간선까지 추가하는 것이 포드 풀커슨 알고리즘의 핵심인 것 같습니다..(잘은 이해안감..ㅠㅠ)


처리부분입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    //process
    int total_flow = 0;
    const int start = ctoi('A'), end = ctoi('Z');
 
    while (1) {
        for (int i = 0; i < MAX_SIZE; i++) prev[i] = -1;
 
        queue<int> q;
        q.push(start);
 
        while (!q.empty())
        {
            int curr = q.front();
            q.pop();
 
            for (int i = 0; i < adj[curr].size(); i++) {
                int next = adj[curr][i];
 
                if (capacity[curr][next] - flow[curr][next] > 0 && prev[next] == -1) {
                    q.push(next);
                    prev[next] = curr;
                    if (next == endbreak;
                }
            }
        }
 
        if (prev[end== -1break//Z까지 가는 길이 없으면..
 
        //A에서 Z로 가는 경로 중에서 가장 작은 용량을 선택    
        int min_flow = INF;
        for (int i = end; i != start; i = prev[i])
            min_flow = min(min_flow, capacity[prev[i]][i] - flow[prev[i]][i]);
 
        //A에서 Z로 가는 경로에 물을 흘림
        //지나간 경로의 반대 경로에는 -값의 물을 흘림
        for (int i = end; i != start; i = prev[i]) {
            flow[prev[i]][i] += min_flow;
            flow[i][prev[i]] -= min_flow;
        }
        
        total_flow += min_flow;
    }
cs

start, end는 시작과 끝점 입니다. 이 문제에서는 'A'와 'Z'가 되겠습니다.

bfs를 통해서 A->Z로 가는 경로를 찾습니다.

경로는 prev배열에 현재 정점 바로 전의 정점을 저장을 해서 경로를 알 수 있습니다.


예를 들어 A->B->C 라면 prev[A] = -1, prev[B] = A, prev[C] = B 입니다.

최종 도착지점은 항상 'Z'이므로 Z부터 역으로 추적하면 A까지 도달할 수 있습니다.


16번째 줄이 굉장히 중요합니다.

1
2
3
4
5
6
7
8
9
for (int i = 0; i < adj[curr].size(); i++) {
    int next = adj[curr][i];
 
    if (capacity[curr][next] - flow[curr][next] > 0 && prev[next] == -1) {
        q.push(next);
        prev[next] = curr;
        if (next == endbreak;
    }
}
cs


curr(현재 정점)에서 연결되어 있는 부분을 탐색합니다.


curr->next의 edge에 용량이 꽉 차지 않았다면 그리고 아직 방문하지 않았다면

if (capacity[curr][next] - flow[curr][next] > 0 && prev[next] == -1)

next 정점을 q에 넣고 prev[다음 정점] = 현재 정점 을 넣어줍니다.

만약 다음 정점이 'Z'(end)라면 루프를 빠져나옵니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        if (prev[end== -1break//Z까지 가는 길이 없으면..
 
        //A에서 Z로 가는 경로 중에서 가장 작은 용량을 선택    
        int min_flow = INF;
        for (int i = end; i != start; i = prev[i])
            min_flow = min(min_flow, capacity[prev[i]][i] - flow[prev[i]][i]);
 
        //A에서 Z로 가는 경로에 물을 흘림
        //지나간 경로의 반대 경로에는 -값의 물을 흘림
        for (int i = end; i != start; i = prev[i]) {
            flow[prev[i]][i] += min_flow;
            flow[i][prev[i]] -= min_flow;
        }
        
        total_flow += min_flow;
cs


주석을 달아 놓은 것처럼

1번째 줄은 정점 'Z'(end)의 이전 정점이 -1라는 것은 bfs에서 Z로 도달하지 못했음을 의미합니다.

그렇기 때문에 더이상 경로가 없음을 의미해서 break;합니다.


그게 아니라면 4번째 줄

bfs로 찾은 경로 구간 중에서 가장 용량이 작은 구간을 선택합니다.

유량을 가장 작은 용량으로 맞춰야만 그 경로로 흘릴 수 있기 때문입니다.

만약 이전 bfs에서 유량이 있을 수 있으므로 최소 용량은 capacity[이전 정점][현재 정점] - flow[이전 정점][현재 정점]으로 구해야 합니다.


그리고


10번째 줄에서 A->Z까지의 경로에 위에서 찾은 min_flow(가장 작은 유량)을 더합니다.

여기서 중요한 부분은 12번째 줄입니다. 경로의 반대 방향으로 -유량을 더해줍니다.

위의 input부분에서 역방향 간선까지 함께 만든 이유입니다.


capacity[curr][next] - flow[curr][next] > 0

아까 이 부분에서 0보다 크면 큐에다가 next를 푸시했는데요.

만약 flow[curr][next]가 -유량이라면 +가 되기 때문에 항상 흐를 수 있습니다.


예시를 보면서 이해하도록 하겠습니다.

이 예시는

http://blog.naver.com/PostView.nhn?blogId=kks227&logNo=220804885235

를 참고 했으며 제가 설명하는 것 보다 훨씬 상세하게 설명해주셨습니다. 저도 이 블로그를 보고 이해했습니다.


지저분해도 .. 이해해주세요!


bfs로



이 경로까지는 찾으셨을텐데요..


이 유량을 다합치면 9가 되죠.

이게 최대일 것 같지만 그렇지 않습니다.


A->E->F->D->B->G->Z의 경로로 1만큼 흘린다면 Z에 최대 10까지 도달할 수 있습니다.


저는 여기서 D->B구간이 이해가 안갔는데..

이 부분이 -유량을 흘린 이유입니다.

B->D구간의 유량은 3이 흐르고 있습니다.

D->B구간은 애초에 경로가 없습니다. 어떻게 흐를까요?


사실.. 진짜로 흐르는 것이 아니라 B->D구간을 상쇄시키는 느낌??적인 느낌입니다.

D->B구간으로 1을 흘려보내면 B->D구간에서 원래 3이 흐르고 있었으니.. 2가 되겠죠!


그리고 그 B->D에서 상쇄시킨 그 1을  B->G 구간으로 보내는 것입니다!!!!!....

느낌만 이해했습니다.. 완전 이해는 아닌..

어떻게 이런거 까지 생각해냈는지는 잘 모르겠네요...ㅠㅠㅠ

제가 참고하라고 올려드린 블로그..

http://blog.naver.com/PostView.nhn?blogId=kks227&logNo=220804885235

를 참조해주세요!!!!!! 정말 잘 설명해주셨습니다..


아래는 풀 코드입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
input)
11
A B 3
A C 3
A D 4
B E 2
C B 10
C E 1
D F 5
E D 1
E F 1
E Z 2
F Z 5
output)
7
*/
 
#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
 
#define MAX_SIZE 52
#define INF 0x7fffffff
 
using namespace std;
 
int ctoi(char c) {
    if (c <= 'Z'return c - 'A';
    return c - 'a' + 26;
}
 
int main() {
    int n;
    vector<int> adj[MAX_SIZE]; // 인접
    int capacity[MAX_SIZE][MAX_SIZE] = { 0, }; // 용량
    int flow[MAX_SIZE][MAX_SIZE] = { 0, }; // 흐르는 양
    int prev[MAX_SIZE]; // 경로를 저장(현재 정점의 이전 정점이 무엇이었는지)
 
    //입력
    scanf("%d"&n);
    getchar();
 
    for (int i = 0; i < n; i++) {
        char s, e;
        int c;
 
        scanf("%c %c %d"&s, &e, &c);
        getchar();
 
        s = ctoi(s), e = ctoi(e); //입력 받은 정점을 숫자로 변환
 
        //같은 간선이 여러개 들어오면 용량이 그만큼 늘어나면 됨
        capacity[s][e] += c;
 
        //정,역방향 간선 추가
        adj[s].push_back(e);
        adj[e].push_back(s);
    }
 
    //process
    int total_flow = 0;
    const int start = ctoi('A'), end = ctoi('Z');
 
    while (1) {
        for (int i = 0; i < MAX_SIZE; i++) prev[i] = -1;
 
        queue<int> q;
        q.push(start);
 
        while (!q.empty())
        {
            int curr = q.front();
            q.pop();
 
            if (curr == endbreak;
 
            for (int i = 0; i < adj[curr].size(); i++) {
                int next = adj[curr][i];
 
                if (capacity[curr][next] - flow[curr][next] > 0 && prev[next] == -1) {
                    q.push(next);
                    prev[next] = curr;
                }
            }
        }
 
        if (prev[end== -1break//Z까지 가는 길이 없으면..
 
        //A에서 Z로 가는 경로 중에서 가장 작은 용량을 선택    
        int min_flow = INF;
        for (int i = end; i != start; i = prev[i])
            min_flow = min(min_flow, capacity[prev[i]][i] - flow[prev[i]][i]);
 
        //A에서 Z로 가는 경로에 물을 흘림
        //지나간 경로의 반대 경로에는 -값의 물을 흘림
        for (int i = end; i != start; i = prev[i]) {
            flow[prev[i]][i] += min_flow;
            flow[i][prev[i]] -= min_flow;
        }
        
        total_flow += min_flow;
    }
 
    printf("%d\n", total_flow);
 
    return 0;
}
cs


'알고리즘 > 네트워크 플로우' 카테고리의 다른 글

[12843] 복수전공  (0) 2017.08.24
[1671] 상어의 저녁식사  (0) 2017.07.02
[1017] 소수 쌍  (0) 2017.06.27

삼성전자 면접 준비 하느라고 블로그 활동을 못했네요.

오랜만에 글 올립니다.

------------------------

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


이 문제는 2가지 절차로 풀었습니다.

1. 대륙마다 번호 붙이기.

2. 대륙끼리 가장 짧은 길이로 연결하기.


input을 받을 때 1이라면 land라는 벡터에 x, y 값을 넣었습니다.

그 후에 land_mark()라는 함수를 통해서 각 대륙마다 번호를 바꿔줍니다. (map[][]에 저장됨.)

번호를 붙인 후 바다와 연결된 대륙이라면(주변에 0이 있으면) bfs를 통해서 자신과 다른 대륙 넘버를 만나면 return해주는 dist()라는 함수를 이용합니다.


아래는 코드입니다.

궁금하신 것은 댓글 달아주세요.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <cstdio>
#include <iostream>
#include <list>
#include <queue>
#include <string.h>
#define MAX_SIZE 100
#define INF 0x7fffffff
 
using namespace std;
 
 
//input
int n;//맵크기
int map[MAX_SIZE][MAX_SIZE];//맵
 
//process
int visit[MAX_SIZE][MAX_SIZE];//방문체크
vector<pair<intint> > land;//땅을 저장할 벡터
int land_number;//땅마다 넘버 붙이기
int visit_number;//방문체크 넘버
 
//direct
int dx[4= {001-1};
int dy[4= {1-100};
 
//땅마다 넘버붙이기 함수
void land_mark(int x, int y)
{
    if(visit[x][y] == 1return;
    visit[x][y] = 1;
 
    queue<pair<intint> > q;
    q.push(make_pair(x, y));
 
    while(!q.empty())
    {
        x = q.front().first;
        y = q.front().second;
        q.pop();
 
        map[x][y] = land_number;
 
        for(int i = 0; i < 4; i++)
        {
            int nx = x + dx[i];
            int ny = y + dy[i];
 
            if(nx < 0 || ny < 0 || nx >= n || ny >= n || visit[nx][ny]) continue;
            if(!map[nx][ny]) continue;
            visit[nx][ny] = 1;
 
            q.push(make_pair(nx, ny));
 
        }
    }
 
    land_number++;
}
 
//거리를 측정하는 bfs함수 ln은 랜드 넘버
int dist(int x, int y, int ln)
{
    bool flag = 0;
    for(int i = 0; i < 4; i++)
    {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if(nx < 0 || ny < 0 || nx >= n || ny >= n) continue;
        if(map[nx][ny] == 0)
        {
            flag = 1;
            break;
        }
    }
 
    if(!flag) return INF;//네 방향에 바다가 없으면 리턴
    visit_number++;
 
    queue<pair<pair<intint>int> > q;
    q.push(make_pair(make_pair(x, y), 0));
 
    while(!q.empty())
    {
        x = q.front().first.first;
        y = q.front().first.second;
        int weight = q.front().second;
        q.pop();
 
 
        for(int i = 0; i < 4; i++)
        {
            int nx = x + dx[i];
            int ny = y + dy[i];
 
            if(nx < 0 || ny < 0 || nx >= n || ny >= n || visit[nx][ny] == visit_number) continue;
 
            if(map[nx][ny] == ln) continue;
            else if(map[nx][ny] != ln && map[nx][ny] != 0return weight;
 
            visit[nx][ny] = visit_number;
            q.push(make_pair(make_pair(nx, ny), weight + 1));
        }
    }
 
    return INF;
}
 
 
int main()
{
 
    scanf("%d"&n);
 
    for(int i = 0; i < n; i++)
    {
        for(int j = 0; j < n; j++)
        {
            scanf("%d"&map[i][j]);
            if(map[i][j] == 1) land.push_back(make_pair(i, j));
        }
    }
 
    land_number = 1;
 
    for(int i = 0; i < land.size(); i++) land_mark(land[i].first, land[i].second);
 
    memset(visit, 0sizeof(visit));
    int ret = INF;
 
    for(int i = 0; i < land.size(); i++)
    {
        int x = land[i].first;
        int y = land[i].second;
        ret = min(ret, dist(x, y, map[x][y]));
    }
 
    printf("%d\n", ret);
 
 
    return 0;
 
}
 
cs


'알고리즘 > 탐색' 카테고리의 다른 글

[1058] 친구  (0) 2017.07.20
[1941] 소문난 칠공주  (1) 2017.07.01
[14503] 로봇 청소기  (2) 2017.04.18
[14502] 연구소  (5) 2017.04.18
[14501] 퇴사  (4) 2017.04.17

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


이 문제가 어려운 이유는 반대쪽 저울에 추를 올릴 수 있다는 점입니다.

문제의 예제처럼 1과 4의 추가 있을 때 검사할 수 있는 무게는


0, 1, 4

그리고

(1 + 4), (4 - 1)


이렇게 다섯가지 입니다. 어려운 부분은 (4 - 1)이겠죠.


문제의 조건을 보면 추의 최대 개수 30개, 추의 최대 무게 500g, 확인할 무게 최대 7개입니다.


dp정의는 dp[n][k] = n번 추까지 사용했을 때 k라는 무게를 만들 수 있는지 (bool) 입니다.


n번째 추에서 나눠지는 경우는 세가지가 있습니다. 추를 왼쪽 저울에 올릴지, 안올릴지, 아니면 오른쪽 저울(편의상 검사할 무게를 오른쪽)에 올릴지 입니다.


이렇게 한다면 시간복잡도는 30개 * 3가지 경우 * 15000(500g * 30)입니다만... 저는 dp배열을 30001로 잡았습니다.

이유는 -값도 저장하기 위해서입니다. dp[][15000]이 0의 무게를 나타내며 14999는 -1, 15001은 1입니다. 30000이면 15000이겠죠??


아래는 풀코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
 
using namespace std;
 
bool dp[31][30001];
int weight[31];
int m[3= {-101};
 
int main()
{
    int n;
    scanf("%d"&n);
 
    for(int i = 1; i <= n; i++scanf("%d"&weight[i]);
 
    dp[0][15000= 1// 0은 추가 없어도 만들 수 있음.
    for(int i = 1; i <= n; i++// i번째 추
    {
        for(int j = 0; j < 3; j++)//-1, 0, 1
        {
            for(int k = 0; k <= 30000; k++// -15000 ~ 15000
            {
                int tt = weight[i] * m[j] + k; // k무게에다가 해당 추를 왼쪽 혹은 오른쪽저울에 올리던지 아니면 안올리던지
                dp[i][tt] += dp[i - 1][k]; // i - 1번째 인덱스까지 k무게가 존재한다면 dp[i][tt]도 존재하게 됨.
            }
        }
    }
 
 
    int nn;
    scanf("%d"&nn);
 
    for(int i = 0; i < nn; i++)
    {
        int ret;
        scanf("%d"&ret);
        printf("%c ", dp[n][ret + 15000] ? 'Y' : 'N');
    }
 
    puts("");
    return 0;
}
 
cs


'알고리즘 > 다이나믹 프로그래밍(DP)' 카테고리의 다른 글

[1029] 그림 교환  (0) 2017.06.27
[1915] 가장 큰 정사각형  (0) 2017.06.07
[2133] 타일 채우기  (0) 2017.04.20
[1309] 동물원  (0) 2017.04.20
[2294] 동전 2  (0) 2017.04.19

노드 구조체

1
2
3
4
5
6
typedef struct _node
{
    int data;
    struct _node* left;
    struct _node* right;
} Node;
cs


리스트 구조체

1
2
3
4
5
6
typedef struct _list
{
    Node* head;
    Node* tail;
    int size;
} List;
cs


List* create_list() : 리스트 생성 및 초기화

1
2
3
4
5
6
7
8
9
List* create_list()
{
    List* new_list = (List*)malloc(sizeof(List));
    new_list->head = NULL;
    new_list->tail = NULL;
    new_list->size = 0;
 
    return new_list;
}
cs


bool list_empty(List* L) : 리스트가 비어있으면 1 아니면 0 리턴

1
2
3
4
5
bool list_empty(List* L)
{
    if(L->sizereturn 0;
    else return 1;
}
cs


Node* create_node(int data) : 노드 생성 및 초기화

1
2
3
4
5
6
7
8
9
Node* create_node(int data)
{
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->data = data;
    new_node->left = NULL;
    new_node->right = NULL;
 
    return new_node;
}
cs


void push_back(List *L, int data) : 리스트 맨 뒤에 푸시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void push_back(List *L, int data)
{
    Node* new_node = create_node(data);
 
    if(list_empty(L))
    {
        L->head = new_node;
        L->tail = new_node;
    }
    else
    {
        L->tail->right = new_node;
        new_node->left = L->tail;
 
        L->tail = new_node;
    }
 
    L->size++;
}
 
cs


void push_front(List *L, int data) : 리스트 맨 앞에 푸시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void push_front(List *L, int data)
{
    Node* new_node = create_node(data);
 
    if(list_empty(L))
    {
        L->head = new_node;
        L->tail = new_node;
    }
    else
    {
        L->head->left = new_node;
        new_node->right = L->head;
 
        L->head = new_node;
    }
 
    L->size++;
}
 
cs


void node_insert(List* L, int idx, int data) : 해당 인덱스에 데이터 삽입

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void node_insert(List* L, int idx, int data)
{
    if(idx == 0) push_front(L, data);
    else if(idx >= L->size - 1push_back(L, data);
    else
    {
        Node* new_node = create_node(data);
 
        Node* now = L->head;
        for(int i = 0; i < idx; i++) now = now->right;
 
        new_node->left = now->left;
        new_node->right = now;
        now->left = new_node;
        new_node->left->right = new_node;
        L->size++;
    }
 
}
cs


void pop_back(List* L) : 리스트 맨 뒤에 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void pop_back(List* L)
{
    if(!list_empty(L))
    {
        if(L->size == 1)
        {
            free(L->head);
            L->head = NULL;
            L->tail = NULL;
        }
        else
        {
            Node* prev = L->tail->left;
            free(L->tail);
            prev->right = NULL;
            L->tail = prev;
        }
        L->size--;
    }
}
cs


void pop_front(List* L) : 리스트 맨 앞에 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void pop_front(List* L)
{
    if(!list_empty(L))
    {
        if(L->size == 1)
        {
            free(L->head);
            L->head = NULL;
            L->tail = NULL;
        }
        else
        {
            Node* next = L->head->right;
            free(L->head);
            next->left = NULL;
            L->head = next;
        }
        L->size--;
    }
}
cs


void node_delete(List* L, int idx) : 입력된 인덱스의 노드 삭제(인덱스가 벗어나면 맨 앞 혹은 맨 뒤 삭제)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void node_delete(List* L, int idx)
{
    if(!list_empty(L))
    {
        if(idx >= L->size - 1) pop_back(L);
        else if(idx <= 0) pop_front(L);
        else
        {
            Node* now = L->head;
            for(int i = 0; i < idx; i++) now = now->right;
 
            now->left->right = now->right;
            now->right->left = now->left;
 
            free(now);
            L->size--;
        }
    }
}
cs


실행 환경 cpp

풀 코드 및 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include <cstdio>
#include <cstdlib>
 
typedef struct _node
{
    int data;
    struct _node* left;
    struct _node* right;
} Node;
 
typedef struct _list
{
    Node* head;
    Node* tail;
    int size;
} List;
 
List* create_list()
{
    List* new_list = (List*)malloc(sizeof(List));
    new_list->head = NULL;
    new_list->tail = NULL;
    new_list->size = 0;
 
    return new_list;
}
 
Node* create_node(int data)
{
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->data = data;
    new_node->left = NULL;
    new_node->right = NULL;
 
    return new_node;
}
 
bool list_empty(List* L)
{
    if(L->sizereturn 0;
    else return 1;
}
 
void push_back(List *L, int data)
{
    Node* new_node = create_node(data);
 
    if(list_empty(L))
    {
        L->head = new_node;
        L->tail = new_node;
    }
    else
    {
        L->tail->right = new_node;
        new_node->left = L->tail;
 
        L->tail = new_node;
    }
 
    L->size++;
}
 
void push_front(List *L, int data)
{
    Node* new_node = create_node(data);
 
    if(list_empty(L))
    {
        L->head = new_node;
        L->tail = new_node;
    }
    else
    {
        L->head->left = new_node;
        new_node->right = L->head;
 
        L->head = new_node;
    }
 
    L->size++;
}
 
void list_print(List* L)
{
    Node* tmp = L->head;
 
    while(tmp)
    {
        printf("%d ", tmp->data);
        tmp = tmp->right;
    }
    puts("");
}
 
void pop_back(List* L)
{
    if(!list_empty(L))
    {
        if(L->size == 1)
        {
            free(L->head);
            L->head = NULL;
            L->tail = NULL;
        }
        else
        {
            Node* prev = L->tail->left;
            free(L->tail);
            prev->right = NULL;
            L->tail = prev;
        }
        L->size--;
    }
}
 
void pop_front(List* L)
{
    if(!list_empty(L))
    {
        if(L->size == 1)
        {
            free(L->head);
            L->head = NULL;
            L->tail = NULL;
        }
        else
        {
            Node* next = L->head->right;
            free(L->head);
            next->left = NULL;
            L->head = next;
        }
        L->size--;
    }
}
 
void node_delete(List* L, int idx)
{
    if(!list_empty(L))
    {
        if(idx >= L->size - 1) pop_back(L);
        else if(idx <= 0) pop_front(L);
        else
        {
            Node* now = L->head;
            for(int i = 0; i < idx; i++) now = now->right;
 
            now->left->right = now->right;
            now->right->left = now->left;
 
            free(now);
            L->size--;
        }
    }
}
 
void node_insert(List* L, int idx, int data)
{
    if(idx == 0) push_front(L, data);
    else if(idx >= L->size - 1push_back(L, data);
    else
    {
        Node* new_node = create_node(data);
 
        Node* now = L->head;
        for(int i = 0; i < idx; i++) now = now->right;
 
        new_node->left = now->left;
        new_node->right = now;
        now->left = new_node;
        new_node->left->right = new_node;
        L->size++;
    }
 
}
 
int main()
{
    List* new_list = create_list();
 
    for(int i = 1; i < 10; i++)
    {
        push_back(new_list, i);
        list_print(new_list);
    }
    for(int i = -10; i < 0; i++)
    {
        push_front(new_list, i);
        list_print(new_list);
    }
    for(int i = 0; i < 20; i++)
    {
        pop_front(new_list);
        list_print(new_list);
    }
 
    for(int i = 1; i < 10; i++)
    {
        push_back(new_list, i);
        list_print(new_list);
    }
 
    for(int i = 0; i < 10; i++)
    {
        node_delete(new_list, i);
        list_print(new_list);
    }
 
    for(int i = 1; i < 10; i++)
    {
        push_back(new_list, i);
        list_print(new_list);
    }
 
    puts("");
    for(int i = 2; i < 5; i++){
        node_insert(new_list, i, -1 - i);
        list_print(new_list);
    }
    return 0;
}
 
 
cs


'CS기본지식 > 자료구조' 카테고리의 다른 글

[C언어] 우선순위 큐(Priority Queue)  (3) 2017.09.07
[2263] 트리의 순회  (1) 2017.08.27
스택 계산기  (0) 2017.06.13
[1918] 후위표기식  (2) 2017.06.13
단순 연결 리스트  (0) 2017.04.22

노드 구조체

1
2
3
4
5
typedef struct _node
{
    int data;
    struct _node* next;
} Node;
cs


리스트 구조체

1
2
3
4
5
typedef struct _list
{
    Node* head;
    int size;
} List;
cs


List* create_list() : 리스트를 만들고 주소를 리턴

1
2
3
4
5
6
7
8
List* create_list()
{
    List* new_list = (List*)malloc(sizeof(List));
    new_list->head = NULL;
    new_list->size = 0;
 
    return new_list;
}
cs


Node* create_node(int data) : 노드를 만들고 주소를 리턴

1
2
3
4
5
6
7
8
Node* create_node(int data)
{
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->data = data;
    new_node->next = NULL;
 
    return new_node;
}
cs


bool list_empty(List* L) : 리스트의 size가 0이면 1을 리턴 아니면 0을 리턴

1
2
3
4
5
bool list_empty(List* L)
{
    if(L->sizereturn 0;
    else return 1;
}
cs


void push_back(List* L, int data) : 리스트의 맨 뒤에 데이터 삽입

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void push_back(List* L, int data)
{
    Node* new_node = create_node(data);
    Node* tmp = L->head;
 
    if(list_empty(L)) L->head = new_node;
    else
    {
        while(tmp->next) tmp = tmp->next;
        tmp->next = new_node;
    }
 
    L->size++;
}
cs


void node_insert(List* L, int idx, int data) : idx가 범위를 리스트 사이즈보다 크거나 같으면 push_back호출 아니면 해당 idx에 삽입

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void node_insert(List* L, int idx, int data)
{
    if(idx >= L->sizepush_back(L, data);
    else
    {
        Node* new_node = create_node(data);
 
        if(idx == 0)
        {
            new_node->next = L->head;
            L->head = new_node;
        }
        else
        {
            Node* tmp = L->head;
            for(int i = 0; i < idx - 1; i++) tmp = tmp->next;
 
            new_node->next = tmp->next;
            tmp->next = new_node;
        }
        L->size++;
    }
}
cs


void node_delete(List* L, int idx) : idx가 범위를 벗어나면 맨 뒤를 삭제 아니면 해당 idx 노드 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
void node_delete(List* L, int idx)
{
    if(!list_empty(L))
    {
        Node* tmp = L->head;
 
        if(idx == 0)
        {
            L->head = tmp->next;
            free(tmp);
        }
        else if(idx >= L->size - 1)
        {
            Node* before = NULL;
            while(tmp->next)
            {
                before = tmp;
                tmp = tmp->next;
            }
 
            free(tmp);
            if(before != NULL) before->next = NULL;
            else L->head = NULL;
        }
        else
        {
            Node* before = NULL;
            for(int i = 0; i < idx; i++)
            {
                before = tmp;
                tmp = tmp->next;
            }
 
            before->next = tmp->next;
            free(tmp);
        }
 
        L->size--;
    }
}
cs


void list_print(List* L) : 리스트 데이터 전부 출력

1
2
3
4
5
6
7
8
9
10
11
void list_print(List* L)
{
    Node *tmp = L->head;
 
    while(tmp)
    {
        printf("%d ", tmp->data);
        tmp = tmp->next;
    }
    puts("");
}
cs


아래는 풀 코드 및 예제입니다.

실행 환경 cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <cstdio>
#include <cstdlib>
 
typedef struct _node
{
    int data;
    struct _node* next;
} Node;
 
typedef struct _list
{
    Node* head;
    int size;
} List;
 
List* create_list()
{
    List* new_list = (List*)malloc(sizeof(List));
    new_list->head = NULL;
    new_list->size = 0;
 
    return new_list;
}
 
Node* create_node(int data)
{
    Node* new_node = (Node*)malloc(sizeof(Node));
    new_node->data = data;
    new_node->next = NULL;
 
    return new_node;
}
 
bool list_empty(List* L)
{
    if(L->sizereturn 0;
    else return 1;
}
 
void push_back(List* L, int data)
{
    Node* new_node = create_node(data);
    Node* tmp = L->head;
 
    if(list_empty(L)) L->head = new_node;
    else
    {
        while(tmp->next) tmp = tmp->next;
        tmp->next = new_node;
    }
 
    L->size++;
}
 
void node_insert(List* L, int idx, int data)
{
    if(idx >= L->sizepush_back(L, data);
    else
    {
        Node* new_node = create_node(data);
 
        if(idx == 0)
        {
            new_node->next = L->head;
            L->head = new_node;
        }
        else
        {
            Node* tmp = L->head;
            for(int i = 0; i < idx - 1; i++) tmp = tmp->next;
 
            new_node->next = tmp->next;
            tmp->next = new_node;
        }
        L->size++;
    }
}
 
void node_delete(List* L, int idx)
{
    if(!list_empty(L))
    {
        Node* tmp = L->head;
 
        if(idx == 0)
        {
            L->head = tmp->next;
            free(tmp);
        }
        else if(idx >= L->size - 1)
        {
            Node* before = NULL;
            while(tmp->next)
            {
                before = tmp;
                tmp = tmp->next;
            }
 
            free(tmp);
            if(before != NULL) before->next = NULL;
            else L->head = NULL;
        }
        else
        {
            Node* before = NULL;
            for(int i = 0; i < idx; i++)
            {
                before = tmp;
                tmp = tmp->next;
            }
 
            before->next = tmp->next;
            free(tmp);
        }
 
        L->size--;
    }
}
 
 
void list_print(List* L)
{
    Node *tmp = L->head;
 
    while(tmp)
    {
        printf("%d ", tmp->data);
        tmp = tmp->next;
    }
    puts("");
}
 
 
int main()
{
    List* new_list = create_list();
    for(int i = 0; i < 10; i++push_back(new_list, i);
    for(int i = 0; i < 10; i++){
        node_delete(new_list, i);
        list_print(new_list);
        printf("size = %d\n", new_list->size);
    }
    return 0;
}
 
 
cs


'CS기본지식 > 자료구조' 카테고리의 다른 글

[C언어] 우선순위 큐(Priority Queue)  (3) 2017.09.07
[2263] 트리의 순회  (1) 2017.08.27
스택 계산기  (0) 2017.06.13
[1918] 후위표기식  (2) 2017.06.13
이중 연결 리스트  (0) 2017.04.22

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



이 문제의 핵심은 맨 위칸 혹은 맨 아래칸이 전부 2 * 1의 타일로 채워졌을 때 입니다. 물론 2 * 1 타일 개수는 2개 이상일 때!

2개 일 때 2개! 3개일 때도 2개, 4개일 때도 2개 !!


그러므로 점화식은 아래와 같습니다!


1
2
3
4
5
    for(int i = 3; i <= n; i++){
        dp[i] += dp[i - 2* 3;
        
        for(int j = 4; j <= i; j += 2) dp[i] += dp[i - j] * 2;
    }
cs


위의 점화식은 2칸일 때 3가지의 경우가 존재하므로 !


아래 점화식은 위에서 설명한 경우 입니다.!


풀코드입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstdio>
#define MAX_SIZE 31
 
int dp[MAX_SIZE];
 
int main()
{
    int n;
    scanf("%d"&n);
 
    dp[0= 1;
    dp[1= 0;
    dp[2= 3;
    for(int i = 3; i <= n; i++){
        dp[i] += dp[i - 2* 3;
        
        for(int j = 4; j <= i; j += 2) dp[i] += dp[i - j] * 2;
    }
 
    printf("%d\n", dp[n]);
 
    return 0;
}
 
cs


'알고리즘 > 다이나믹 프로그래밍(DP)' 카테고리의 다른 글

[1915] 가장 큰 정사각형  (0) 2017.06.07
[2629] 양팔 저울  (0) 2017.04.25
[1309] 동물원  (0) 2017.04.20
[2294] 동전 2  (0) 2017.04.19
[2293] 동전 1  (4) 2017.04.19

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


다른 분들은.. 도대체 어떻게 푸신건지.. 잘 이해가 안가더라구요...ㅎㅎ...

저는.. 좀 어렵게 푼듯 하네요... 다른분들은 1차원 dp인데 저는 2차원 dp라고 생각했습니다.


dp[N][3]으로 2차원 dp를 정의했고

N은 칸 수 뒤의 3은


0 = N번째 칸에 사자를 안넣는 경우

1 = 1번째 칸에 사자를 넣는 경우

2 = 2번쨰 칸에 사자를 넣는 경우


라고 생각하고 풀었습니다.


n칸에다가 사자를 안넣는다면

dp[n][0]은 dp[n - 1][0] + dp[n - 1][1] + dp[n - 2][2]입니다.

n칸에다가 사자를 안넣는 경우는 n - 1 칸에서 사자를 안넣는경우, 사자를 1칸에 넣는 경우, 2칸에 넣는경우 셋 다 가능하기 때문입니다.


n의 1칸에 사자를 넣는다면 n-1칸에서는 사자를 안넣거나 2칸에 넣는다면 n의 1칸에 사자를 넣을 수 있으므로 그 두개를 더합니다.


n의 2칸에서는 1칸과 동일하게 n - 1칸에 사자를 안넣는 경우, 1칸에 넣는 경우 두가지를 더합니다.


점화식은..

1
2
3
4
5
6
for(int i = 2; i <= n; i++)
{
    dp[i][0= dp[i - 1][0+ dp[i - 1][1+ dp[i - 1][2];
    dp[i][1= dp[i - 1][0+ dp[i - 1][2];
    dp[i][2= dp[i - 1][0+ dp[i - 1][1];
}
cs

입니다!


아래는 풀 코드입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <cstdio>
#define MAX_SIZE 100001
 
int dp[MAX_SIZE][3];
 
int main()
{
    int n;
    scanf("%d"&n);
 
    for(int i = 0; i < 3; i++) dp[1][i] = 1;
 
    for(int i = 2; i <= n; i++)
    {
        dp[i][0= dp[i - 1][0+ dp[i - 1][1+ dp[i - 1][2];
        dp[i][1= dp[i - 1][0+ dp[i - 1][2];
        dp[i][2= dp[i - 1][0+ dp[i - 1][1];
 
        for(int j = 0; j < 3; j++) dp[i][j] %= 9901;
    }
    printf("%d\n", (dp[n][0+ dp[n][1+ dp[n][2])%9901);
 
    return 0;
}
 
cs


'알고리즘 > 다이나믹 프로그래밍(DP)' 카테고리의 다른 글

[2629] 양팔 저울  (0) 2017.04.25
[2133] 타일 채우기  (0) 2017.04.20
[2294] 동전 2  (0) 2017.04.19
[2293] 동전 1  (4) 2017.04.19
[1727] 커플 만들기  (0) 2017.04.05

+ Recent posts