[풀이]백준 풀이(XIII/15683 등)
문제풀이
감시(15683, 시뮬레이션)
- N*M 형태의 이차원 배열
- CCTV는 5가지 종류(1한방향, 2양쪽방향, 3직각방향, 4세방향, 5네방향)
- 6은 벽이다.
-
사무실의 크기와 상태, CCTV가 주어졌을 때 CCTV의 방향을 적절히 정해서 최소 사각지대의 크기를 구하는 프로그램을 작성하라.
- 1<=N,M <=8
- CCTV는 8개를 넘지 않는다.
풀이
- 중복순열이 필요하다 (next_permutation은 그냥 순열!)
- 백준15651 참조!
- 외울게 늘었네 ㅎㅎ.. (DFS를 이용한 순열구하기!)
DFS를 짜되 VISITED를 표시하지 않으면 된다.
문법…헷갈려 아래 둘은 같은 뜻
for (auto i : vc)
printf("%d ", i);
printf("\n");
return;
int size = vc.size();
for(int i=0; i<size; i++){
cout << vc[i] << " ";
}
cout << endl;
return;
중단
회고
- 사람은 실수를 한다…
- 시험장가서도 이럴거같은데 걱정이네.
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <tuple>
#include <algorithm>
#define NEWS 4
#define INF 987654321
using namespace std;
int cx, cy;
int n, m, cctv, Answer = INF;
int office[9][9];
int officeTemp[9][9];
vector<int> vc;
//<type, cx, cy>
queue<tuple<int, int, int>> tv;
queue<tuple<int, int, int>> tvTemp;
queue<int> rotateInfo;
//이게 0부터가면 되는게 아니라
void watchLeft(int x, int y) {
if (office[x][y - 1] == 6) return;
for (int i = y; i >= 0; i--) {
//벽이면 끝내
if (office[x][i] == 6) {
i = -1;
}
//아니면 -1(#)으로 채우자
else if (office[x][i] == 0) office[x][i] = -1;
}
}
void watchRight(int x, int y) {
if (office[x][y +1] == 6) return;
for (int i = y; i < m; i++) {
//벽이면 끝내
if (office[x][i] == 6) i = m;
//아니면 -1(#)으로 채우자
else if (office[x][i] == 0) office[x][i] = -1;
}
}
void watchUp(int x, int y) {
if (office[x-1][y] == 6) return;
for (int i = x; i >= 0; i--) {
//벽이면 끝내
if (office[i][y] == 6) i = -1;
//아니면 -1(#)으로 채우자
else if (office[i][y] == 0) office[i][y] = -1;
}
}
void watchDown(int x, int y) {
if (office[x +1][y] == 6) return;
for (int i = x; i < n; i++) {
//벽이면 끝내
if (office[i][y] == 6) i = n;
//아니면 -1(#)으로 채우자
else if (office[i][y] == 0) office[i][y] = -1;
}
}
void makeBlindSpot(int type, int degree) {
if (type == 1)
{
//R
if (degree == 1)watchRight(cx, cy);
//D
if (degree == 2)watchDown(cx, cy);
//L
if (degree == 3)watchLeft(cx, cy);
//U
if (degree == 4)watchUp(cx, cy);
}
if (type == 2)
{
//LR
if (degree % 4 == 1) {
watchLeft(cx, cy);
watchRight(cx, cy);
}
//UD
if (degree % 4 == 2) {
watchUp(cx, cy);
watchDown(cx, cy);
}
}
if (type == 3)
{
//UR
if (degree == 1) {
watchUp(cx, cy);
watchRight(cx, cy);
}
//RD
if (degree == 2) {
watchRight(cx, cy);
watchDown(cx, cy);
}
//DL
if (degree == 3) {
watchDown(cx, cy);
watchLeft(cx, cy);
}
//LU
if (degree == 4) {
watchLeft(cx, cy);
watchUp(cx, cy);
}
}
if (type == 4)
{
//LUR
if (degree == 1) {
watchLeft(cx, cy);
watchUp(cx, cy);
watchRight(cx, cy);
}
//URD
if (degree == 2) {
watchUp(cx, cy);
watchRight(cx, cy);
watchDown(cx, cy);
}
//RDL
if (degree == 3) {
watchRight(cx, cy);
watchDown(cx, cy);
watchLeft(cx, cy);
}
//DLU
if (degree == 4) {
watchDown(cx, cy);
watchLeft(cx, cy);
watchUp(cx, cy);
}
}
}
void findBlindSpot() {
int compAns = 0;
int type;
int degree;
while (!rotateInfo.empty())
{
//tv = cctv 종류 && 위치
//rotateInfo = 회전(방향) (1 = 90, 2 = 180, 3 = 270)
tuple<int, int, int> k = tv.front();
tie(type, cx, cy) = k;
degree = rotateInfo.front();
if (cx == 2 && cy == 3 && type == 1 && degree == 3) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (office[i][j] == 0) compAns++;
}
}
}
if (type != 6) makeBlindSpot(type, degree);
//큐에서 빼고
tv.pop();
rotateInfo.pop();
}
//tv 비워보자..
while (!tv.empty()) {
tv.pop();
}
//사각지대를 찾고
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (office[i][j] == 0) compAns++;
}
}
Answer = min(Answer, compAns);
//tv 갱신
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
office[i][j] = officeTemp[i][j];
if (office[i][j] > 0 && office[i][j] != 6) {
tv.push(tuple<int, int, int>(office[i][j], i, j));
}
}
}
}
void dfs()
{
//예외1 만약 현재최소값이 0이면 더작아질 수 없으므로 끝낸다.
if (Answer == 0) {
return;
}
//cctv 개수
cctv = tv.size();
int size = vc.size();
if (size == cctv)
{
//회전정보 저장
for (int i = 0; i < size; i++) {
rotateInfo.push(vc[i]);
}
//사각지대를 찾는다.
findBlindSpot();
return;
}
for (int i = 1; i <= NEWS; i++)
{
if (size < cctv)
{
vc.push_back(i);
dfs();
vc.pop_back();
}
}
}
int main()
{
int Atemp = 0;
ios_base::sync_with_stdio(NULL);
cin.tie(NULL);
cin >> n >> m;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> office[i][j];
//카메라가 없는 경우를 대비하여 미리 처리
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (office[i][j] == 5) {
watchUp(i, j);
watchRight(i, j);
watchDown(i, j);
watchLeft(i, j);
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
officeTemp[i][j] = office[i][j];
//카메라가 하나도 없을 경우에 대비해서
if (office[i][j] == 0) Atemp++;
if (office[i][j] > 0) {
if (office[i][j] != 6) tv.push(tuple<int, int, int>(office[i][j], i, j));
}
}
}
//미리 0의 개수를 세놓는다.
Answer = min(Atemp, Answer);
dfs();
cout << Answer;
return 0;
}
계란으로 계란치기(16987)
- 계란은 내구도, 무게를 가지고 있다.
- 계란끼리 부딪히면 상대의 무게만큼 내구도가 깎인다.
-
내구도가 0이하가 되면 계란은 깨진다.
- 가장 왼쪽 계란부터 시작
- 깨지지 않은 다른 계란 중 하나를 친다.
- 모든 계란이 깨졌다면 PASS
- 손에 든 계란이 깨졌다면 PASS
- 가장 최근에 든 계란의 한 칸 오른쪽 계란을 들고 깨지지 않은 계란 중 하나를 친다.
-
가장 최근에 든 계란이 가장 오른쪽에 위치한 계란일 경우 종료한다.
- 최대한 많은 계란을 깨고싶다.
ㅇ ㅇ ㅇ ㅇ ㅇ ㅇ 맨 왼쪽거 들고 랜덤으로 친다. 원래 자리에 내려놓고 다음 계란을 든다. 즉, 모든 계란으로 한 번씩 칠 수도 있다.
연습하기 int형태 dfs 짜기
#include<iostream>
#include<vector>
#include<tuple>
#include<queue>
#include<algorithm>
using namespace std;
int n;
//index, durability, weight
queue<tuple<int, int, int>> eggs;
vector<tuple<int, int, int>> eggsTemp;
vector<pair<int, int>> dw;
vector<int> arrForNP;
bool destroyed[8];
int durable[8];
int weight[8];
int Answer = 0;
int result = 0;
bool isDestroyed(int x) {
if (durable[x] <= 0) {
destroyed[x] = true;
return true;
}
else {
destroyed[x] = false;
return false;
}
}
bool isAllDestroyed(int hand) {
for (int i = 0; i < n; i++) {
if (durable[hand] == i) continue;
else if (durable[i] > 0) return false;
}
return true;
}
bool isFight(int x, int y) {
if (!isDestroyed(x) && !isDestroyed(y) ) return true;
else return false;
}
bool isInside(int hand) {
if (hand < n) return true;
else return false;
}
void printState(int hand, int i) {
for (int i = 0; i < n; i++) {
int tmp = 0;
if (durable[i] <= 0) tmp++;
result = max(result, tmp);
}
}
void collide(int hand) {
//중복이 허용이 돼야한다.
for (int i = 0; i < n; i++) {
//손에 들었으므로 자기자신은 제외
if (hand == i) continue;
if (!isInside(hand)) return;
else {
//모든 계란이 깨졌다. 또는 마지막 계란까지 다 쳤으면
if (isAllDestroyed(hand) || hand==n+1) {
printState(hand, i);
result = max(result, Answer);
return;
}
else {
//안깨진놈들끼리면
if (isFight(hand, i)) {
//부딪혔으면 서로 빼라.
durable[hand] -= weight[i];
durable[i] -= weight[hand];
bool handTmp = false;
bool iTmp = false;
if (isDestroyed(hand)) {
Answer++;
handTmp = true;
}
if (isDestroyed(i)) {
Answer++;
iTmp = true;
}
//손에든걸로 다음꺼 부쉈으면 다다음껄로 시작
if ( (i-hand)==1 && isDestroyed(i)) {
collide(hand + 2);
}
else {
collide(hand + 1);
}
printState(hand, i);
result = max(result, Answer);
//원상복구 (여기서 부숴졌으면 돌려놔)
if (isDestroyed(hand) && handTmp) Answer--;
if (isDestroyed(i) && iTmp) Answer--;
durable[hand] += weight[i];
durable[i] += weight[hand];
}
}
}
}
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
int j, k;
cin >> j >> k;
durable[i] = j;
weight[i] = k;
}
collide(0);
cout << result;
}
댓글남기기