반응형
문제 출처 :
https://www.acmicpc.net/problem/1799
알고리즘 분석 :
문제 해결에 필요한 사항
1. 이분 매칭 :: http://www.crocus.co.kr/499
이 문제를 풀고 있다면 룩 시리즈 문제를 꼭 풀어보길 바란다.
룩 시리즈 문제 :: http://www.crocus.co.kr/search/rook
체스판 문제는 이분 매칭 문제로 연결 할 수 있고, 룩, 비숍 등등 문제 접근법만 알아낸다면 똑같은 코드가 계속 재활용된다.
룩의 경우에는 행 / 열에 대해 넘버링을 하여 이분 매칭을 하지만,
비숍의 경우에는 대각선으로 움직이기에 대각선을 기준으로 넘버링을 해야한다.
넘버링 이후 이제 벽이 아닌 것들에 대해 이분 그래프를 형성해 주면 된다.
위의 그래프를 토대로 이분 그래프를 형성 한 후 아래 이분 매칭을 하게되면 예제 입력 값의 결과가 된다.
즉, 왼쪽 그래프의 1번과 오른쪽 그래프의 5번이 있는 곳에 비숍을 놓으면 된다는 의미가 되는 것이다.
(그렇게 계속 반복)
소스 코드 :
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 | #include <iostream> #include <cstdio> #include <vector> #define max(a,b)(a > b ? a : b) #define MAX_N 52 #define MAX_V 102 using namespace std; vector<int> adj[MAX_V]; vector<int> aMatch; vector<int> bMatch; int map[MAX_N][MAX_N]; int visit[MAX_V]; int visitCnt; int Left[MAX_N][MAX_N]; int Right[MAX_N][MAX_N]; int n, m; void fillLeft(); void fillRight(); void checkLeftandRight(); bool dfs(int a) { if (visit[a] == visitCnt) return false; visit[a] = visitCnt; for (int next = 0; next < adj[a].size(); next++) { int b = adj[a][next]; if (bMatch[b] == -1 || dfs(bMatch[b])) { aMatch[a] = b; bMatch[b] = a; return true; } } return false; } int bipartiteMatch() { aMatch = vector<int>(n + 1, -1); bMatch = vector<int>(m + 1, -1); int size = 0; for (int a = 1; a <= n; a++) { visitCnt++; size += dfs(a); } return size; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) scanf("%d", &map[i][j]); fillLeft(); fillRight(); // checkLeftandRight(); // 1일때만 간선 연결(0일때는 벽이니) int maxL = 0, maxR = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (map[i][j] == 1) { adj[Left[i][j]].push_back(Right[i][j]); maxL = max(maxL, Left[i][j]); maxR = max(maxR, Right[i][j]); } // 이분매칭에 이용 될 n과 m은 maxL, maxR로 교체된다. n = maxL; m = maxR; int get = bipartiteMatch(); printf("%d", get); return 0; } void fillLeft() { int y = 1; int x = n; int cnt = 1; // 오른쪽 위 시작 기준 대각선은 총 n번 반복 for (int k = 0; k < 2*n-1; k++) { int tmpy = y; int tmpx = x; while (tmpy <= n) Left[tmpy++][tmpx++] = cnt; cnt++; x--; } } void fillRight() { int y = n; int x = n; int cnt = 1; // 오른쪽 아래 시작 기준 대각선은 총 n번 반복 for (int k = 0; k < 2*n-1; k++) { int tmpy = y; int tmpx = x; while (tmpy > 0) Right[tmpy--][tmpx++] = cnt; cnt++; x--; } } void checkLeftandRight() { cout << endl; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) cout << Left[i][j] << " "; cout << endl; } cout << endl; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) cout << Right[i][j] << " "; cout << endl; } } // This source code Copyright belongs to Crocus // If you want to see more? click here >> | Crocus |
반응형
'Applied > 알고리즘 문제풀이' 카테고리의 다른 글
[1560번] 비숍 (0) | 2017.04.16 |
---|---|
[2570번] 비숍2 (0) | 2017.04.16 |
[9525번] 룩 배치하기 (0) | 2017.04.15 |
[11444번] 피보나치 수 6 (0) | 2017.04.15 |
[2749번] 피보나치 수 3 (0) | 2017.04.15 |