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

 

5014번: 스타트링크

첫째 줄에 F, S, G, U, D가 주어진다. (1 ≤ S, G ≤ F ≤ 1000000, 0 ≤ U, D ≤ 1000000) 건물은 1층부터 시작하고, 가장 높은 층은 F층이다.

www.acmicpc.net

 

문제

강호는 코딩 교육을 하는 스타트업 스타트링크에 지원했다. 오늘은 강호의 면접날이다. 하지만, 늦잠을 잔 강호는 스타트링크가 있는 건물에 늦게 도착하고 말았다.

스타트링크는 총 F층으로 이루어진 고층 건물에 사무실이 있고, 스타트링크가 있는 곳의 위치는 G층이다. 강호가 지금 있는 곳은 S층이고, 이제 엘리베이터를 타고 G층으로 이동하려고 한다.

보통 엘리베이터에는 어떤 층으로 이동할 수 있는 버튼이 있지만, 강호가 탄 엘리베이터는 버튼이 2개밖에 없다. U버튼은 위로 U층을 가는 버튼, D버튼은 아래로 D층을 가는 버튼이다. (만약, U층 위, 또는 D층 아래에 해당하는 층이 없을 때는, 엘리베이터는 움직이지 않는다)

강호가 G층에 도착하려면, 버튼을 적어도 몇 번 눌러야 하는지 구하는 프로그램을 작성하시오. 만약, 엘리베이터를 이용해서 G층에 갈 수 없다면, "use the stairs"를 출력한다.

입력

첫째 줄에 F, S, G, U, D가 주어진다. (1 ≤ S, G ≤ F ≤ 1000000, 0 ≤ U, D ≤ 1000000) 건물은 1층부터 시작하고, 가장 높은 층은 F층이다.

출력

첫째 줄에 강호가 S층에서 G층으로 가기 위해 눌러야 하는 버튼의 수의 최솟값을 출력한다. 만약, 엘리베이터로 이동할 수 없을 때는 "use the stairs"를 출력한다.

 

접근방법 및 풀이

- BFS를 이용하여 버튼를 누르는 최소횟수를 탐색한다.

- 탐색 중 도착한 층은 방문체크한다.

- 버튼을 누르는 경우 유효층으로 이동(방문이 안되었고 1층이상 F층 이하)가능하면 이동한다.

- 목표층에 도달할때 까지 진행한 후 찾지 못했다면 use the stairs를 출력한다.

 

#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define VMAX 1000001

using namespace std;

int height;
int src, dst;
int u,d;
int v[VMAX]={0};
int result=-1;

void bfs(){
    queue<pair<int,int>> q;
    q.push({src, 0});
    v[src]=1;
    while(!q.empty()){
        int x = q.front().first;
        int c = q.front().second;
        q.pop();
        if(x==dst){
            result = max(result, c);
        }
        if(x+u <= height && v[x+u]==0){
            v[x+u]=1;
            q.push({x+u, c+1});
        }
        if(x-d >= 1 && v[x-d]==0){
            v[x-d]=1;
            q.push({x-d, c+1});
        }
    }
}

int main()
{
    cin >> height >> src >> dst >> u >> d;
    if(src == dst){
        printf("0");
        return 0;
    }
    bfs();
    
    if(result==-1){
        cout << "use the stairs";
    }else{
        cout << result;
    }
    return 0;
}

 

느낀점

- bfs가 어떤 해를 찾는 문제에 대해 생각보다 많이 쓰일 것 같다는 생각이 들었다.

'알고리즘 문제풀이' 카테고리의 다른 글

[백준] 11048번 이동하기 c++  (0) 2021.08.06
[백준] 2573번 빙산 c++  (0) 2021.08.06
[백준] 2468번 안전 영역 c++  (0) 2021.08.05
[백준] 2644번 촌수계산 c++  (0) 2021.08.05
[백준] 2307번 도로검문 c++  (0) 2021.08.02

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

 

2468번: 안전 영역

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는

www.acmicpc.net

 

문제

재난방재청에서는 많은 비가 내리는 장마철에 대비해서 다음과 같은 일을 계획하고 있다. 먼저 어떤 지역의 높이 정보를 파악한다. 그 다음에 그 지역에 많은 비가 내렸을 때 물에 잠기지 않는 안전한 영역이 최대로 몇 개가 만들어 지는 지를 조사하려고 한다. 이때, 문제를 간단하게 하기 위하여, 장마철에 내리는 비의 양에 따라 일정한 높이 이하의 모든 지점은 물에 잠긴다고 가정한다.

어떤 지역의 높이 정보는 행과 열의 크기가 각각 N인 2차원 배열 형태로 주어지며 배열의 각 원소는 해당 지점의 높이를 표시하는 자연수이다. 예를 들어, 다음은 N=5인 지역의 높이 정보이다.

6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

이제 위와 같은 지역에 많은 비가 내려서 높이가 4 이하인 모든 지점이 물에 잠겼다고 하자. 이 경우에 물에 잠기는 지점을 회색으로 표시하면 다음과 같다. 

6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

물에 잠기지 않는 안전한 영역이라 함은 물에 잠기지 않는 지점들이 위, 아래, 오른쪽 혹은 왼쪽으로 인접해 있으며 그 크기가 최대인 영역을 말한다. 위의 경우에서 물에 잠기지 않는 안전한 영역은 5개가 된다(꼭짓점으로만 붙어 있는 두 지점은 인접하지 않는다고 취급한다). 

또한 위와 같은 지역에서 높이가 6이하인 지점을 모두 잠기게 만드는 많은 비가 내리면 물에 잠기지 않는 안전한 영역은 아래 그림에서와 같이 네 개가 됨을 확인할 수 있다. 

6 8 2 6 2
3 2 3 4 6
6 7 3 3 2
7 2 5 3 6
8 9 5 2 7

이와 같이 장마철에 내리는 비의 양에 따라서 물에 잠기지 않는 안전한 영역의 개수는 다르게 된다. 위의 예와 같은 지역에서 내리는 비의 양에 따른 모든 경우를 다 조사해 보면 물에 잠기지 않는 안전한 영역의 개수 중에서 최대인 경우는 5임을 알 수 있다. 

어떤 지역의 높이 정보가 주어졌을 때, 장마철에 물에 잠기지 않는 안전한 영역의 최대 개수를 계산하는 프로그램을 작성하시오.

입력

첫째 줄에는 어떤 지역을 나타내는 2차원 배열의 행과 열의 개수를 나타내는 수 N이 입력된다. N은 2 이상 100 이하의 정수이다. 둘째 줄부터 N개의 각 줄에는 2차원 배열의 첫 번째 행부터 N번째 행까지 순서대로 한 행씩 높이 정보가 입력된다. 각 줄에는 각 행의 첫 번째 열부터 N번째 열까지 N개의 높이 정보를 나타내는 자연수가 빈 칸을 사이에 두고 입력된다. 높이는 1이상 100 이하의 정수이다.

출력

첫째 줄에 장마철에 물에 잠기지 않는 안전한 영역의 최대 개수를 출력한다.

 

접근방법 및 풀이

- 안전영역의 수를 개산하기 위해 BFS를 사용하였다.

- 물의 높이가 최소1부터 최대 100까지 이므로 100가지의 경우의 물의 상태에 대해 모두 고려해준다.

- 각각의 경우에 대해 지역들이 물에 잠기는지 여부를 초기화해준 후 BFS를 진행한다.

#include <iostream>
#include <algorithm>
#include <queue>

#define VMAX 101

using namespace std;

int n;
int b[VMAX][VMAX];
int v[VMAX][VMAX];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};

void bfs(int sx, int sy){
    queue<pair<int, int>> q;
    q.push({sx,sy});
    v[sx][sy] = 1;
    while(!q.empty()){
        int x = q.front().first;
        int y = q.front().second;
        q.pop();
        for(int i=0; i<4; i++){
            int X = x + dx[i];
            int Y = y + dy[i];
            if(X>=0 && Y>=0 && X<n && Y<n){
                if(v[X][Y]==0){
                    v[X][Y]=1;
                    q.push({X,Y});
                }
            }
        }
    }
}


int main()
{
    cin >> n;
    int result=0;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
            scanf("%d", &b[i][j]);
        }
    }
    for(int k=0; k<=100; k++){ // 물높이 0 부터 100까지 각각의 경우의 집합수를 구한다.
        int temp=0;
        for(int i=0; i<n; i++){ // 물높이에 따른 v배열 즉 물의 잠기는 지역을 표시한다..
            for(int j=0; j<n; j++){
                v[i][j]=0;
            }
        }
        for(int i=0; i<n; i++){ // 물높이에 따른 v배열 즉 물의 잠기는 지역을 표시한다..
            for(int j=0; j<n; j++){
                if(b[i][j] <= k){
                    v[i][j] = 1;
                }
            }
        }
        
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++){
                if(v[i][j] == 0){
                    bfs(i,j);
                    temp++;
                }
            }
        }
        result = max(result, temp);
    }
    cout << result;

    return 0;
}

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

 

2644번: 촌수계산

사람들은 1, 2, 3, …, n (1 ≤ n ≤ 100)의 연속된 번호로 각각 표시된다. 입력 파일의 첫째 줄에는 전체 사람의 수 n이 주어지고, 둘째 줄에는 촌수를 계산해야 하는 서로 다른 두 사람의 번호가 주어

www.acmicpc.net

 

문제

우리 나라는 가족 혹은 친척들 사이의 관계를 촌수라는 단위로 표현하는 독특한 문화를 가지고 있다. 이러한 촌수는 다음과 같은 방식으로 계산된다. 기본적으로 부모와 자식 사이를 1촌으로 정의하고 이로부터 사람들 간의 촌수를 계산한다. 예를 들면 나와 아버지, 아버지와 할아버지는 각각 1촌으로 나와 할아버지는 2촌이 되고, 아버지 형제들과 할아버지는 1촌, 나와 아버지 형제들과는 3촌이 된다.

여러 사람들에 대한 부모 자식들 간의 관계가 주어졌을 때, 주어진 두 사람의 촌수를 계산하는 프로그램을 작성하시오.

입력

사람들은 1, 2, 3, …, n (1 ≤ n ≤ 100)의 연속된 번호로 각각 표시된다. 입력 파일의 첫째 줄에는 전체 사람의 수 n이 주어지고, 둘째 줄에는 촌수를 계산해야 하는 서로 다른 두 사람의 번호가 주어진다. 그리고 셋째 줄에는 부모 자식들 간의 관계의 개수 m이 주어진다. 넷째 줄부터는 부모 자식간의 관계를 나타내는 두 번호 x,y가 각 줄에 나온다. 이때 앞에 나오는 번호 x는 뒤에 나오는 정수 y의 부모 번호를 나타낸다.

각 사람의 부모는 최대 한 명만 주어진다.

출력

입력에서 요구한 두 사람의 촌수를 나타내는 정수를 출력한다. 어떤 경우에는 두 사람의 친척 관계가 전혀 없어 촌수를 계산할 수 없을 때가 있다. 이때에는 -1을 출력해야 한다.

 

문제접근 및 풀이

- DFS 혹은 BFS를 사용하여 간단히 풀수 있다.

- 촌수를 계산해야 하는 두 사람을 각각 시작과 끝 노드로 두어 탐색을 진행한다.

 

#include <iostream>
#include <vector>
#include <queue>
#define VMAX 101

using namespace std;

vector<int> a[VMAX];
int v[VMAX]={0};

int bfs(int src, int dst){
  queue<pair<int, int>> q;
  q.push({src, 0});
  v[src]=1;
  while(!q.empty()){
    int x = q.front().first;
    int c = q.front().second;
    q.pop();
    if(x==dst){
      return c;
    }
    for(int i=0; i<a[x].size(); i++){
      int y = a[x][i];
      //printf("x:%d y:%d\n",x,y);
      if(v[y]==0){
        v[y]=1;
        q.push({y,c+1});
      }
    }
  }
  
  return -1; 
}

int main(){
  int n; cin >> n;
  int src, dst; cin >> src >> dst;
  int m; cin >> m;
  for(int x,y,i=0; i<m; i++){
    scanf("%d %d", &x, &y);
    a[x].push_back(y);
    a[y].push_back(x);
  }
  int result = bfs(src, dst);
  printf("%d", result);
}
*/

 

책을 쓴 이유

1. 국민이 정부의 재정활동의 내용을 알면 정부는 절대 국민에게 함부로 하지 못한다.

2. 정부가 제공하는 재화와 서비스의 가치를 제대로 알아야 한다. 정보비대칭으로 인한 국민의 효용감소를 막자.

-> 효용감소 : 적은 세금, 적은 복지를 원하는 한국국민

 

1부 재정, 이렇게 움직인다

chapter1 정부의 역할

- 정부의 정책과 사업은 국민들의 생활에 광범위한 영향을 미친다.

- 2010년 국가재정은 약 300조 GDP의 28%이다. 국민의 세금이 곧 국가의 제정이다.

 

정부의 경제활동

1. 3가지 기본활동

1) 자원분배

- 공공재의 공급 및 제공. 시장이 제대로 하지 못하는 일을 하기 위함이다.

- 공공재란? 공동구매/공동소비해야 하는 것들. 시장에서 수급이 이루어지기 힘든 재화 및 서비스를 말한다. ex. 도로,치안,국방,항만 등

 

2) 경제안정 및 성장

- 경제안정과 성장을 위한 기반을 마련한다.

- 연구개발, 인프라 구축, 경기부양, 가치재 제공 등

- 가치재란? 대한민국 국민이라면 마땅히 누려야할 일정수준의 혜택 ex. 의료,교육

 

3) 소득분배

- 소득분배 개선을 통한 빈부격차 완화

 

2. 조세지출

- 조세지출 : 면제를 통해 세금을 걷지 않는 것을 말한다.

- 수혜자에게 해당 금액만큼의 보조금을 지급하는 효과가 발생한다.

- 하지만 행위가 비가지적인 탓에 통제가 약하고 비효율적이다. -> 방만하게될 가능성이 높다.

 

3. 규제자로서의 정부

- 규제를 통해 민간 경제에 영향을 준다.

- 민간경제 주체들 사이의 이득과 손해를 유발하기에 매우 중요하다. -> 정부의 영량이 중요한 이유이다.

 

chapter2 예산의 흐름

- 예산 : 세출예산 + 세입예산이다.

- 세출예산은 어디에 얼마나 쓸지 세입예산은 어디에서 얼마나 걷을지에 관한 것이다.

1. 일반회계

- 특정목적이 없는 예산이다. 국방,치안,외교 등 다양한 분야에 사용된다.

- 편성과정

1) 정부가 기획재정부에 예산신청

2) 기획재정부가 검토 후 부서별 배정

3) 국회의결

4) 확정

 

2. 특별회계

- 특정 사업을 위해 할당되는 예산이다.

- 편성과정 : 개별부처 소관이다. 일반회계와 승인과정은 같지만 이미 재원이 확보된 사업이기에 더 편하다.

- 그만큼 예산이 비효율적으로 쓰이고 낭비될 가능성이 크다.

- 폐지불가능성이 크고 각 사업마다 이익집단이 존재하기 때문에 주의가 요해진다.

 

3. 기금

- 국민연금, 고용보험 등 자체 수입원을 가지며 운용의 제량권이 인정된다.

 

-> 우리나라 국회는 예산에 대한 권한이 별로 없는 ㅂ편이다. 예산안 국회수정비율이 1%이하이다.

-> 정부재원은 예산 + 기금이다.

 

chapter3 세입과 세출

우리나라 세입과 세출의 특성

세입예산 = 조세 + 세외수입 + 기금수입

1. 조세 : 소득세, 법인세, 부가가치세 등

2. 세외수입 : 국가재산의 임대, 매매수입, 수수료, 벌금 등

3. 기금수입 : 사횝보험료, 각종부담금(11년 기준 부담금 97개 항목, 14조)

 

- 조세부담률 : GDP대비 조세비율

-> 10년 기준 OECD평균 : 24.7%, 한국 19.3%

- 국민부담률 : GDP대비 조세+사회보험료의 비율

-> 10년 기준 OECD평군 : 33.8%, 한국:25.0%

조세부담률과 국민부담률이 낮은 편이다.

 

소득세

- 우리나라 조세의 특징은 소득세가 낮다는 것이다. 근로소득세는 누진세로 구간별로 내기 때문에, 그리고 다양한 소득공제 혜택이 있기 때문에 실제 납부하는 실효세율이 명목세율에 비해 상당히 낮다.

- 실효세율이 소득수준에 관계없이 터국에 비해 크게 낮다.

- 소득세율이 일정하게 낮으면 고소득층일수록 혜택이 크다.

 

법인세

- 법인세도 마찬가지로 공제혜택이 많아 실효세율이 낮고 대기업일 수록 공제혜택을 많이 받는다.

- 특정 소득공재 항목은 대기업에 유리하게 작용하기도 한다.(투자세액공제, 연구및인력개발비세액공제 등)

 

세출예산

- 정부지출은 크게 4가지 국방(10.1%), 일방행정(22.4%), 경제개발(22.2%), 사회개발(45.4%)로 구성된다.  -> 12년 기준

- 95년 대비 12년에 경제개발비용이 57.2%->22.2% 사회개발비용이 20.0%->45.7%로 변화했다는 것이 특징이다.

- 국방 및 R&D관련 예산은 속성상 효과성 파악이 힘들다.

- R&D 12년 기준 예산의 4.9%인것은 비중이 높은 편이다.

- 복지지출 120조원, 전체 지출의1/3, GDP대비 10%이지만 OECD국가 중 매우 작은 규모이다.

- 복지지출은 국가존립에 필수 기능이 아니므로 국가,사회 구성원의 가치관, 역사적 상황에 따라 달라진다.

 

복지 지출 충당 방법

1. 조세부담률을 높인다.

2. 다른분야의 예산을 줄려 복지에 충당한다.

 

- 조세증가에 대해 국민의 불신과 저항이 있다. 국민부담금을 늘린다면 어떤 항목을 늘려야 할까? -> chapter4

 

chapter4 조세의 원칙

- 세금은 민생과 직결된 문제이다.

- 정부는 재원마련을 위해 과제하며 조세부담 수준에 따라 정부지출 규모도 달라진다.

- 핵심은 공평성, 공정성이다.

- 세금은 공공재에 대한 대가인데 각 개인이 공공재로부터 얻는 혜택을 측정할 수가 없다. 또한 국방,치안처럼 소득에 따라 받는 혜택의 양도 다르다.

-> 편익 법칙 적용이 힘들며, 담세능력에 비례하여 세금을 내야 한다!

 

담세능력원칙

1.수직적 공평성

- 담세능력이 많을수록 세금을 많이 내야한다.

- 우리나라는 소득세에 대해 누진세를 적용한다.

 

2. 수평적 공평성

- 만약 담세능력이 같다면 동일 세금을 부과한다.

- 소득이 같아도 지출수요에 따라 담세능력이 달리진다. 이를 고려하기 위한 것이 소득공제제도이다!

 

소득공제제도

- 담세능력의 차이를 반영하기 위해 특정소득을 소득에서 공제한 후 과제를 한다.

- 부양가족 당 일정금액, 일정규모의 의료비, 교육비 등이 해당된다.

- 정부가 특정목적 달성을 위한 유인책으로 쓰기도 한다.

1) 행동유도 : 연금세득공제, 연구세액공제 등

2) 활동억제 : 술,담배에 대한 중과세부과

 

과세와 효율성

- 과제로 인해 노동의지를 꺾을 수도 있다. 가령 높은 근로소득세는 노동의지를 줄이고 높은 법인소득세는 투자를 위축시키는 것이다.

 

-> 공공재의 소비와 비용부담을 직접연결할 수 없는 것이 정부 비효율성의 근본원인이다. 

 

chapter5 국가채무와 재정위기

국가는 왜 빚을 지는가?

1. 일시적인 지출증가 - 전쟁 등

2. 수입감소 - 경기침체를 극복하기 위해서

3. 미래를 위한 투자 - 경제개발 자금 마련 등

4. 만성적 적자

 

재정적자 -> 국가채무

경상수지 적자 -> 대외채무

 

 

2부 정부가 할 것인가, 시장이 할 것인가

chapter6 고객정치와 예산낭비

정부는 왜 시장보다 비효율적인가?

1. 비용부담자와 혜택수혜자의 불일치

- 공공재의 특성상 산출물의 비용과 혜택이 같은 사람에게 귀속되지 않는다.

2. 성과의 불활실성

- 8조를 국방에 투입하는게 교육에 투입한 것 보다 더 국민을 위한 것인가? 정확히 헤아리기 힘들다.

3. 가격기구가 작동할 수 없다.

- 오로지 이해관계 당사자간에서 결정된다.

1) 정치인(정책결정)

2) 정책대상자(비용부담 및 혜택)

3) 공부원(정책집행)

- 이때 자기 이익우선 심리가 발동되며 자연스레 각종 낭비 및 비효율이 발생한다.

 

- 포퓰리즘

1) 정치적 지지를 얻기 위한 것. ex. 비용다수-편익소수인 고객정치

2) 안 하는 포퓰리즘 : 조세, 사회보험로 인상은 필요하지만 정치적 지지를 위해 하지 않음

 

그렇다면 정부의 효율을 높이려면 어떻게 해야 하나?

 

 

chapter7 비용편익분석과 민자사업

비용편익분석

- 정부가 특정 사업과 정책을 시행하기전 비용편익을 따져보는 것이다.

한계점

- 평가항목 선정이 중요하다. 평가항목을 부적절하게 설정할 수 있다.

- 비화폐적인 요소가 많아 불확실하다. (건강, 업무능률, 화목 등)

 

1. 정부재량으로 하는 경우

- 정부가 정책의 정당화를 위해 사용한다.

- ex. FTA를 체결하면 GDP가 5.97% 증가합니다!!

 

2. 의무적으로 하는 경우

- 예비타당성조사

- 기획재정부 주관 하에 한국개발연구원(KDI)가 실시한다.

- 비용,편익의 규모를 적당히 가감해서 결과를 조정하는 경우가 많다.

 

참고 4대강 사업은 어떻게 예비타당성조사를 받지 않았는가?

: 예비타당성조사 예외조항을 '재해예방복구지원'으로 수정하여 프리패스했다.

 

민자사업(민간투자사업)

- 정부재원 부족을 해결하고 효율성을 높이기 위해 사용한다.

- SOC(사회간접자본)과 공공시설의 건설 및 운영을 민간에 위탁하여 시장을 활용하는 것이다.

종류

1. 수익형 민자사업(BTO, Built-Transfer-Operation)

- 민간이 건설한 후에 정부가 운영권을 갖는 방식으로 재원을 충당한다.

- 도로 건설 후 통행료를 받는 경우이다.

 

2. 입대형 민자사업(BTL, Built-Transfer-Lease)

- 민간이 건설 후 정부가 임대료를 지불하여 사용하는 방식이다.

- 학교기숙사와 군대 숙소 건설 후 임대료를 부여하는 방식이다.

 

- MRG(Minimun Revenue Guarnantee, 최소운영수입보장)제도는 폐지되었지만 여전히 민간기업에 대한 정부의 원가보장의무는 남아있다.

- 재원 조달과 효율성을 위해 하는 것인데 현재까지 들보다 실인 경우가 허다하다.

 

chapter8 민영화

민영화

- 생산은 민간에게 맡기되 수급과정에 정부개입을 통해 공공성을 달성한다는 취지이다.

- 민간에게 위탁 가능한 것에 대해서는 당연히 민간(시장)에게 맡기는 것이 정부보다 효율적이기 때문이다. 제대로 이루어 지면 효율은 좋을 것이다.

요점

1. 성과가 상승한다. 하지만 어디까지나 독단이익을 추구하는 기업에 한정된 성과와 이익이다.

2. 정부규제가 병행되지 않으면 공공성이 훼손된다.

 

의료보험 민영화

- 건강보험을 보충하는 민간보험인 실손보험이 존재한다.

- 건강보험 부담금을 제외한 개인부담금을 커버해 준다.

- 때론 경쟁이 독점보다 못할 수도 있다. -> 민간으로 다수가 갈아탄가면 정부가 공적 서비스의 질을 높일 압박을 받지 못한다.

- 공공의료보험 vs 인간의료보험 대치구도가 형성될 경우 -> 낮은보험금/낮은혜택과 높은보험금/높은혜택으로 이원화된다.

 

가치재 민영화

- 가치재 : 대한민국 국민이라면 마땅히 누려야할 일정수준의 혜택. 교육, 의료 등

- 가치재 공급을 민간이 담당하면 정보비대칭이 필연적이다.

- 소비자가 경쟁업체의 서비스의 질을 파악하고 선택가능해야 하는데 교육,의료 등은 현실적으로 불가능하다.

 

=> 민영화 후 정부가 규제를 제대로 하고 공공병원 및 복지시설을 확충해야 한다.

 

chapter9 지방재정

정부 = 중앙정부 + 지방정부

- 중앙정부와 지방정부는 기능이 다르다.

 

중앙정부의 역할

- 경제안정화, 소득재분배 등 형평성이 문제될 수 있는 것은 중앙정부가 통제한다. -> 국민기본선(전국적 동일한 기준의 혜택)

 

지방정부의 역할

1. 복지사업의 '전달'(대행)

2. 지역에 영향을 미치는 공공재 공급 ex. 생활평의시설 공급

3. 지역 경제 활성화를 위한 지역 사업 ex. 대형 개발 사업

-> 지역주민의 선호 반영이 가능하며 지방정부끼리의 경쟁을 통해 재정운용 효율을 높일 수 있기 때문이다.

 

재산세(부동산), 취득세를 지방세로 하는 이유

- 부동산 가격 결정에 지역 공공재의 역할이 크다고 보기 때문이다.

- 즉 지역성이 강하기 때문이며, 특히 부동산은 거래량이 재마다 크게 달라 격차가 크다.

 

하지만 지방정부간 경쟁으로 인해 지역격차가 발생한다.

지역격차를 줄이기 위해 정부는 교부금와 국고보조금을 지원한다.

1. 교부금

- 지역격차 완화를 위해 공식에 따라 정해진다.

2. 국고보조금

- 국고보조사업 지원 경비이다.

- 국고보조금은 지방정부 재정악화의 원인이 되기도 한다.

- 국고보조사업의 경비는 지방정부와 중앙정부가 함께 충당하기 때문이다. 예컨대 3:7비율로 충당한다. -> 이는 지방정부에게 부담이 될 수 있다.

- 보육료는 국민기본선에 해당하지 않는다는 익식이 강해 국고보조금이 낮다.

 

지방재정위기 원인

1. 국고보조사업

2. 지방정부의 남발하는 개발사업도 예산낭비를 심각하게 만든다.

 

방만한 재정운용을 막기위해서는?

- 투명한 정보공개 : 정보비대칭을 막아야 한다.

- 지방정부와 지역주민이 서로를 잘 알아야 한다. (ps. 주민참여 예산제)

- 주민은 정부의 하는일을 모르고 정부는 주민이 바라는 사업을 모르면...

- 결국 핵심 해결책은 똑똑하고 지역정치에 관심갖는 주민 즉 주민참여이다. 이는 풀뿌리 민주주의의 핵심이다.

 

3부 변화하는 사회, 재정이 중요해진다.

chapter10 1인당 GDP는 느는데 왜 살기는 더 힘들어 질까 | 경제성장과 재정

- 고용불안, 과중한 교육비, 가계 빚 증가(신용카드), 맞벌이 증가, 힘에 부치는 주택장만으로 삶이 더 힘들어졌다.

- 맞벌이는 실제이득은 적지만 GDP는 이중으로 높인다.

- 소득격화가 심화되었고 GDP가 모두 가구소득으로 들어가지 않는다!(기업소득은 높아졌고 가계소득은 줄었다.)

- GDP에서는 오로지 소득만 측정한다. 예컨대 교통사고가 늘어서 정비소와 병원이 돈을 많이 벌면 GDP는 상승한다.

=> GDP에서 개인의 몫은 줄고 소득격차가 커진것이 (1인당 GDP증가 >> 내 소득 증가)인 이유이다.

 

chapter11 일자리가 늘어나도 살기는 힘들어 진다? | 경제구조 변화와 재정

탈산업화

- 산업구조가 제조업 중심에서 서비스업 중심으로 변화했다. 부가가치의 창출 원천이 노동/자본에서 지식으로 변화되었다. 이는 곧 소득 양극화, 고용불안, 맞벌이 증가를 낳았다.

- 자동화로 인한 생산성 증가로 인해 제조업 고용률은 낮아졌고 서비스업 고용을 늘었다. 즉 로우테크(질 낮은)일자리들만 늘어나 소득격차의 심화를 촉발하였다.

=> 탈산업화로 인해 부의 총량은 늘었지만, 창출 일자리 다수는 로우테크이다. 시장의 실패이다. 이에 따라 정부의 역할이 중요해진다.

 

정부가 해야할 것

1. 고용불안/저임금에 대처하기 위한 직업훈련과 취업알선

2. 맞벌이 부부를 위한 보육지원과 노인부양사회화

3. 제대로된 노동 관련 규제 정책 시행

4. 사회급여

=> 일자리 양극화 -> 근로빈곤에 머무르는 다수의 국민들 -> 시장의 실패를 정부가 교정하는 것이 재역할 이다.

 

chapter12 누군가 받으려면 누군가는 내야한다. | 새대 간 분배

고령화와 재정운용

- 고령화가 재정운영을 어렵게하는 이유는 이것이 근로자 감소와 노인부양비용 증가를 야기하기 때문이다.

- 수명연장으로 인해 의퇴 후 다수가 소득없는 노후를 보내 연금지출이 늘어난다.

- 스스로 노후준비를 잘하면 연금이 필요 없지만 현실은 그렇지 않다.

 

의료보험을 강제해야 하는 이유

- 의료는 가치제이다. 모든 국민이 일정 수준 이상의 혜택을 누려야 한다. 

1. 능력있는 사람들은 스스로 충당하게 하고 어려운 사람만 도와주면 재정운영에 도움이 되지 않나? -> 그러면 보험가입을 하지 않으려고 한다.

2. 의료 서비스 제공의 효율성(정부 > 시장)

- 사회 연대의 원칙 : 능력 대로 부담하되 혜택은 함께 누린다.

-> 노후소득/의료보장을 공동으로 대처하자. 이는 복지국가의 근본 이념이다. 이때 세대 간 계약이 발생한다. (노인세대 - 근로세대 - 아동/청소년 세대)

 

세대간 계약의 지속가능성

:세대 간 계약을 이어가기 위해 우리 세대가 할 수 있는 일

1. 연금과 의료 제정 안정화를 위한 개혁

2. 미래의 근로세대를 키우는 것, 즉 출산률을 높이는 것이다. 출산장려!

 

chapter13 바람직한 분배상태는 어떤 것인가? | 재정의 소득분배 기능

- 소득분배는 정부의 기본기능이다.

- 존 롤스의 무지의 장막 : 평등주의 이론 -> 다수가 하위계층의 혜택을 지지한다.

- 대한민국 국민이라면 누구나 일정수준 이상의 생활을 보장받아야 한다.

- 다수가 동의가능한 최저의 분배기준 : 취약계층을 위한 사회안정망을 형성한 후 공정한 기회가 보장되어야 한다.

- 소득분배기능의 핵심은 빈곤층 지원, 그중에서도 노인빈곤층에 대한 지원이 시급하다. -> 연금제도 부실 탓이 크다.

 

4부 재정이 미래를 결정짓는다.

chapter14 복지는 성장에 걸림돌일까? | 복지논쟁

감세정책은 서민과 중산층을 위한것이다?

- 감세의 직접적 혜택은 고소득층일수록 많다. 오리혀 서민과 중산층의 삶은 어려워지고 증세가 이를 해결한다.

- 감세에는 정부의 재정적자가 증가 혹은 낮은 복지라는 결과가 대응된다.

- 감세로 경제활성화를 시킨다는 것은 yes or no 이지만, 감세는 소득분배를 악화시킨다.

 

복지혜택은 생산활동을 가로막는다?

- 우리나라는 조세부담이 낮은 편이다. 조세부담률이 어지간히 높아지지 않는한 근로동기는 낮아지지 않을 것이다.

- 모든 선진국들에 예외없이 복지제도를 발전시킨이유는 이것이 자본주의 발전을 위해 필연적이기 때문이다.

- 계층간의 갈등과 사회혼란을 진정시키며 순조로운 발전이 가능해 진다.

- 복지는 자본주의의 산물이다.

=> 결국 문제는 복지를 어느 수준까지 해야하는가? 이다.

 

복지는 국가재정 위기를 부른다?

- 복지'규모'보다는 지출'내용'이 국가 부채와 연관이 깊다.

- 연금지출이 높을수록 국가부채가 높으며 사회지출이 높을수록 국가 부채가 낮다.

- 복지지출을 국민부담으로 감당하능한지 여부가 중요하다. 즉 세금으로 잘 충당되면 문제없다.

-> 복지확대가 국가의 부채증가로 이어지지 않으려면 연금지출에 대한 대비와 재원조달과 복지확대가 병행되어야 한다. 재원조달 방법마련!

 

우리 재정의 지속가능성

1. 세입을 확대해야 한다.

2. 출산장려해야 한다.

3. 정부가 제대로된 경제적 역할을 수행해야 한다.

4. 무엇보다 국민스스로가 국가제정에 관심가져야 한다.

 

 

 

 

 

 

 

 

 

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

 

2307번: 도로검문

그림 1은 어떤 도시의 주요 지점과 그 지점들 간의 이동시간을 나타낸 그래프이다. 그래프의 노드는 주요 지점을 나타내고  두 지점을 연결한 도로(에지)에 표시된 수는 그 도로로 이동할 때 걸

www.acmicpc.net

문제

그림 1은 어떤 도시의 주요 지점과 그 지점들 간의 이동시간을 나타낸 그래프이다. 그래프의 노드는 주요 지점을 나타내고  두 지점을 연결한 도로(에지)에 표시된 수는 그 도로로 이동할 때 걸리는 분 단위의 시간을 나타낸다. 두 지점 a와 b를 연결하는 도로는 도로(a,b)로 표시한다.

그림 1

예를 들어 도로(1,2)와 도로(2,3)를 통하여 지점1에서 지점3으로 갈 때 걸리는 시간은 3분이다. 도로는 모두 양방향이라고 가정하므로 도로(a,b)와 도로(b,a)를 지날 때 걸리는 시간은 항상 같다고 한다.

어떤 범죄용의자가 입력 데이터에 표시된 도시로 진입하여 이 도시를 가장 빠른 시간 내에 빠져나가고자 한다. 그런데 이 사실을 알고 있는 경찰이 어떤 하나의 도로(에지)를 선택하여 이 도로에서 검문을 하려고 한다. 따라서 용의자는 이 도로를 피해서 가장 빠르게 도시를 탈출하고자 한다. 이 경우 경찰이 검문을 위하여 선택하는 도로에 따라서 용의자의 가장 빠른 탈출시간은 검문이 없을 때에 비하여 더 늘어날 수 있다.

문제는 도로검문을 통하여 얻을 수 있는 탈출의 최대 지연시간을 계산하는 것이다. 추가설명은 다음과 같다.

  1. 두 개의 지점을 직접 연결하는 도로가 있는 경우, 그 도로는 유일하다. 
  2. 도시의 지점(노드)은 1에서 N번까지  N개의 연속된 정수로 표시된다.
  3. 용의자가 도시에 진입하는 지점은  항상 1번이고 도시를 빠져 나가기 위하여 최종적으로 도달해야하는 지점은 항상 N번 지점이다.
  4. 용의자는 검문을 피해서 가장  빨리 도시를 빠져나가고자 하고, 경찰은 적절한 도로를 선택하여 이 용이자들의 탈출시간을 최대한 지연시키고자 한다.
  5. 각 도시 지점 간을 이동하는 시간은 항상 양의 정수이다.

입력 도시의 도로망에 따라서 경찰이 어떤 도로를 막으면 용의자는 도시를 탈출하지 못할 수도 있다. 이 경우 검문으로 인하여 지연시킬 수 있는 탈출시간은 무한대이다. 이 경우에는 -1을 출력해야 한다.

그림 1에서 볼 때 검문이 없을 경우 용의자가 도시를 탈출하는데 걸리는 시간은 4분이다. 만일 경찰이 도로(4,3)을 막으면 그 탈출시간을 지연시킬 수 없으므로 지연시간은 0이다. 만일 도로(2,3)을 막으면, 용의자들이 가장 빠르게 탈출할 수 있는 시간은 5분이므로 탈출지연시간은 1분이고, 도로(3,6)을 막으면 탈출지연시간은 2분이다.

여러분은 입력 데이터에 표시된 도로망을 읽고, 경찰이 한 도로를 막고 검문함으로써 지연시킬 수 있는 최대시간을 정수로 출력하여야한다. 만일 지연효과가 없으면 0을 출력해야하고, 도시를 빠져나가지 못하게 만들 수 있으면(지연시간이 무한대) -1을 출력해야 한다.

입력

첫 줄에는 지점의 수를 나타내는 정수  N(6 ≤ N ≤ 1000)과 도로의 수 M(6 ≤ M ≤ 5000)이 주어진다. 그 다음 이어 나오는 M개의 각 줄에는 도로(a, b)와 그 통과시간 t가 a b t 로 표시된다. 단 이 경우 a < b 이고 1 ≤ t ≤ 10000이다.

출력

경찰이 하나의 도로를 막음으로써 지연시킬 수 있는 최대 시간을 정수로 출력한다. (단, 그 지연시간이 무한대이면 -1을 출력해야 한다.)

 

 

문제접근 및 고려사항, 풀이

- dijkstra algorithm를 응용하여 풀 수 있다.

- 도로는 유일하고 양방향이며, 가중치는 양의정수이다.


- 어떤 도로를 막아 탈출 불가능하게 만들면 -1
- 도로를 막아 탈출시간을 지연할 수 있는 최대값 구하기
- 지연효과가 없으면 0이라는 것이 무엇을 의미하는 지 생각해보니 도로검문 전 부터 아예 탈출 불가능한 경우를 의미하는 것이었다.

 

1. 1번 도시에서부터 n번 도시로의 dijkstras 진행

-> 만약 탈출불가능 한 경우 0 출력(도로검문 없이도 탈출불가능하면 도로검문으로 인한 지연효과가 없으므로)

-> 도로검문 없는 경우의 용의자의 최단경로 값을 확보한다.
2. 1을 진행하면서 opt에 다가 거치는 도로들을 담는다.
3. opt에 담긴 각 도로에 대해 해당 도로를 막는 경우에 대해 dijkstras를 진행하면서 기존 최대값보다 비교하여 최대값을 갱신한다.
-> 만약 탈출불가능 (최대값이 INF)이면 -1
-> INF 아니면 기존 최소값과 차이를 구해서 max와 비교 후 갱신
-> opt는 도로검문 없은 경우의 최단경로로 고려된 도로들의 집합이므로 3에서 구한 최대값이 1에서 구한 최단경로 이동 가중치값과 같을 수 없다.

 

#include <iostream>
#include <vector>
#include <queue>
#define VMAX 1001
#define INF 987654321

using namespace std;

vector<pair<int,int>> v[VMAX];
vector<pair<int,int>> opt;
int dist[VMAX];
int n;

void dijkstras1(int start){
  priority_queue<pair<int,int>> pq;
  for(int i=0; i<=n; i++) dist[i] = INF;
  dist[1]=0;
  pq.push({-0, 1});
  while(!pq.empty()){
    int x = pq.top().second;
    int wx = -pq.top().first;
    pq.pop();
    if(x==n) return ;
    for(int i=0; i<v[x].size(); i++){
      int y = v[x][i].first;
      int wy = v[x][i].second;
      if(dist[y] > dist[x] + wy){
        dist[y] = dist[x] + wy;
        pq.push({-dist[y], y});
        opt.push_back({x,y});
      }
    }
  }
}

void dijkstras2(int start, pair<int,int> a){
  int tx = a.first;
  int ty = a.second;
  priority_queue<pair<int,int>> pq;
  for(int i=0; i<=n; i++) dist[i] = INF;
  dist[1]=0;
  pq.push({-0, 1});
  while(!pq.empty()){
    int x = pq.top().second;
    int wx = -pq.top().first;
    pq.pop();
    if(x==n) return ;
    for(int i=0; i<v[x].size(); i++){
      int y = v[x][i].first;
      int wy = v[x][i].second;
      if(!(y==ty && x==tx) && !(y==tx && x==ty) && dist[y] > dist[x] + wy){
        dist[y] = dist[x] + wy;
        pq.push({-dist[y], y});
      }
    }
  }
}

int main(){
  int m; cin >> n >> m;
  int result=0;
  for(int x,y,w,i=0; i<m; i++){
    scanf("%d %d %d", &x, &y, &w);
    v[x].push_back({y,w});
    v[y].push_back({x,w});
  }
  dijkstras1(1);
  if(dist[n]==INF){
    printf("0");
    return 0;
  }
  int minv = dist[n];

  for(int i=0; i<opt.size(); i++){
    dijkstras2(1, opt[i]);
    if(dist[n]==INF){
      printf("-1");
      return 0;
    }else{
      result = max(result, dist[n] - minv);
    }
  }
  printf("%d", result);
}

느낀점

첫 접근때, 최단경로에 해당하는 도로만을 모아서 하나씩 검문하는 것이 불가능하다고 생각했다. 그래서 모든 도로에 대해 각 도로를 검문하도록 했더니 시간초과가 나왔다. 어떻게 최적화 시킬 수 있을까 하고 고민하다가 1->n으로의 최단경로를 이루는 도로들만을 구하는 것은 어렵겠지만 최단경로를 탐색하는 과정에서 거친 도로들을 모으면 이전보다 최적화될것이라고 생각하고 코드를 짰더니 통과가 되었다. 나름의 고민끝에 이전보다 더 코드를 짜 너무 뿌듯했다.

 

-> 지금 생각해보니,, routing algorithm처럼 각 노드에서 연결된 노드들을 저장시켜서 꼬리물기 방식으로 탐색하면 1->n으로 향하는 최단 경로를 구할 수 있다!

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

 

2156번: 포도주 시식

효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규

www.acmicpc.net

문제

효주는 포도주 시식회에 갔다. 그 곳에 갔더니, 테이블 위에 다양한 포도주가 들어있는 포도주 잔이 일렬로 놓여 있었다. 효주는 포도주 시식을 하려고 하는데, 여기에는 다음과 같은 두 가지 규칙이 있다.

  1. 포도주 잔을 선택하면 그 잔에 들어있는 포도주는 모두 마셔야 하고, 마신 후에는 원래 위치에 다시 놓아야 한다.
  2. 연속으로 놓여 있는 3잔을 모두 마실 수는 없다.

효주는 될 수 있는 대로 많은 양의 포도주를 맛보기 위해서 어떤 포도주 잔을 선택해야 할지 고민하고 있다. 1부터 n까지의 번호가 붙어 있는 n개의 포도주 잔이 순서대로 테이블 위에 놓여 있고, 각 포도주 잔에 들어있는 포도주의 양이 주어졌을 때, 효주를 도와 가장 많은 양의 포도주를 마실 수 있도록 하는 프로그램을 작성하시오. 

예를 들어 6개의 포도주 잔이 있고, 각각의 잔에 순서대로 6, 10, 13, 9, 8, 1 만큼의 포도주가 들어 있을 때, 첫 번째, 두 번째, 네 번째, 다섯 번째 포도주 잔을 선택하면 총 포도주 양이 33으로 최대로 마실 수 있다.

입력

첫째 줄에 포도주 잔의 개수 n이 주어진다. (1≤n≤10,000) 둘째 줄부터 n+1번째 줄까지 포도주 잔에 들어있는 포도주의 양이 순서대로 주어진다. 포도주의 양은 1,000 이하의 음이 아닌 정수이다.

출력

첫째 줄에 최대로 마실 수 있는 포도주의 양을 출력한다.

 

 

문제접근 및 풀이

점화식을 통해 해결한다.

i번째 포도주까지 고려한 경우를 생각해보면

3잔연속으로 마실 수 없으므로 다음 시나리오가 존재한다.

1. i-3번째를 마시고 i-1,i번째를 마신다.

2. i-2번째를 마시고 i번째를 마신다.

3. i-1번째를 마시고 i번째를 마시지 않는다. -> 이게 중요했다. i번째를 마시지않고 i-1를 마시는 경우가 더 큰값을 가질수 있다. -> 여러 잔을 건너뛸수 있기 때문이다.

#include <iostream>
#include <algorithm>

using namespace std;

int main(){
    int n; cin >> n;
    int a[10001]={0};
    int dp[10001]={0};
    for(int i=1; i<=n; i++) scanf("%d", &a[i]);
    dp[0] = 0;
    dp[1] = a[1];
    dp[2] = a[1] + a[2];
    for(int i=3; i<=n; i++){
        dp[i] = max({dp[i-3]+a[i-1]+a[i], dp[i-2]+a[i], dp[i-1]});
    }
    printf("%d\n", dp[n]);
}

 

느낀점

점화식의 위력을 알게 되었다. 항상 재귀로 가지치기하는 식으로 dp문제를 해결했었다. 이 문제도 최적을 해를 점화식을 통해 찾기 보다 처음에, 해당 포도주를 먹는 경우 먹지 않는 경우를 재귀형식으로 하여 모든 가능한 경우중 최대값을 찾으려 하니 자연스레 시간초과가 났다. 하지만 점화식을 찾고 O(n)만에 답을 구할 수 있다는 것에 놀랐다. 더 dp 공부를 해야 겠다.

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

 

9663번: N-Queen

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다. N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

www.acmicpc.net

 

문제

N-Queen 문제는 크기가 N × N인 체스판 위에 퀸 N개를 서로 공격할 수 없게 놓는 문제이다.

N이 주어졌을 때, 퀸을 놓는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N이 주어진다. (1 ≤ N < 15)

출력

첫째 줄에 퀸 N개를 서로 공격할 수 없게 놓는 경우의 수를 출력한다.

 

 

접근방식 및 풀이

백트래킹을 통해 모든경우를 탐색하고 가지치기하며 해를 구해나간다.

1. 1번째 행부터 각 행에 대해 각각 1~n까지의 칸에 퀸이 있는 모든 경우를 탐색한다.

2. 탐색 중 해당칸에 퀸을 놓는 것이 허용되면 놓고 그렇지 않으면 리턴한다. -> 가지치기

3. pos가 n+1까지 다다르면 n개의 퀸을 다 규칙에 맞게 놓게된것을 의미하므로 이때 카운트를 한다.

 

#include <iostream>

using namespace std;

int n, count=0;
int b[15]={0}; // max_N : 14

bool check(int pos){
    for (int i = 1; i < pos; i++) {
		if (b[pos] == b[i] || pos - i == abs(b[pos] - b[i])) {
			return false;
		}
	}
	return true;
}

void bt(int pos){
    if(pos==n+1){
        count++;
        return ;
    }
    
    for(int i=1; i<=n; i++){
        b[pos]=i;
        if(check(pos)==true){
            bt(pos+1);
        }
    }
    
    return ;
}

int main(){
    cin >> n;
    bt(1);
    printf("%d", count);
    return 0;
}

 

느낀점

처음에 2차원 배열로 접근했다. n이 13일때 너무 복잡도가 커지길래 해결방법을 계속 생각해보았다. 더 효율적인 가지치기 방법이 있나에만 집중하다가 결국 해답을 보았고 1차원 배열로도 풀이가 가능하다는 것을 알게 되었다. n-queen풀이의 판이 2차원인 것을 곧이곧대로 받아들인 탓에 유연한 사고를 못한게 아쉬웠다.

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

 

14889번: 스타트와 링크

예제 2의 경우에 (1, 3, 6), (2, 4, 5)로 팀을 나누면 되고, 예제 3의 경우에는 (1, 2, 4, 5), (3, 6, 7, 8)로 팀을 나누면 된다.

www.acmicpc.net

문제

오늘은 스타트링크에 다니는 사람들이 모여서 축구를 해보려고 한다. 축구는 평일 오후에 하고 의무 참석도 아니다. 축구를 하기 위해 모인 사람은 총 N명이고 신기하게도 N은 짝수이다. 이제 N/2명으로 이루어진 스타트 팀과 링크 팀으로 사람들을 나눠야 한다.

BOJ를 운영하는 회사 답게 사람에게 번호를 1부터 N까지로 배정했고, 아래와 같은 능력치를 조사했다. 능력치 Sij는 i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치이다. 팀의 능력치는 팀에 속한 모든 쌍의 능력치 Sij의 합이다. Sij는 Sji와 다를 수도 있으며, i번 사람과 j번 사람이 같은 팀에 속했을 때, 팀에 더해지는 능력치는 Sij와 Sji이다.

N=4이고, S가 아래와 같은 경우를 살펴보자.

i/j

  1 2 3
4   5 6
7 1   2
3 4 5  

예를 들어, 1, 2번이 스타트 팀, 3, 4번이 링크 팀에 속한 경우에 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S12 + S21 = 1 + 4 = 5
  • 링크 팀: S34 + S43 = 2 + 5 = 7

1, 3번이 스타트 팀, 2, 4번이 링크 팀에 속하면, 두 팀의 능력치는 아래와 같다.

  • 스타트 팀: S13 + S31 = 2 + 7 = 9
  • 링크 팀: S24 + S42 = 6 + 4 = 10

축구를 재미있게 하기 위해서 스타트 팀의 능력치와 링크 팀의 능력치의 차이를 최소로 하려고 한다. 위의 예제와 같은 경우에는 1, 4번이 스타트 팀, 2, 3번 팀이 링크 팀에 속하면 스타트 팀의 능력치는 6, 링크 팀의 능력치는 6이 되어서 차이가 0이 되고 이 값이 최소이다.

입력

첫째 줄에 N(4 ≤ N ≤ 20, N은 짝수)이 주어진다. 둘째 줄부터 N개의 줄에 S가 주어진다. 각 줄은 N개의 수로 이루어져 있고, i번 줄의 j번째 수는 Sij 이다. Sii는 항상 0이고, 나머지 Sij는 1보다 크거나 같고, 100보다 작거나 같은 정수이다.

출력

첫째 줄에 스타트 팀과 링크 팀의 능력치의 차이의 최솟값을 출력한다.

 

문제접근 및 풀이

형성가능한 모든 팀 쌍에 대해 점수를 계산하여 각 팀의 점수차가 최소가 되는 값을 구해야 겠다고 생각했다.

1. 백트래킹을 통해 n/2개의 집합을 찾는다. -> nC2

2. 그 후 a팀와 b팀의 팀원간 시너지를 계산한다.

3. 현재까지의 최소값보다 작으면 최소값을 갱신한다.

 

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int s[21][21]={0};
int c[21]={0};
int n, result=987654321;

void bt(int depth, int pos, int c[]){
    if(depth == n/2){
        for(int i=1; i<=n; i++){
            //printf("%d ", c[i]);
        }
        //printf("\n");
        int asum=0, bsum=0;
        for(int i=1; i<=n-1; i++){
            if(c[i]==1){
                for(int j=i+1; j<=n; j++){
                    if(c[j]==1){
                        asum = asum + s[i][j] + s[j][i];
                    }
                }
            }else{
                for(int j=i+1; j<=n; j++){
                    if(c[j]==0){
                        bsum = bsum + s[i][j] + s[j][i];
                    }
                }
            }
        }
        result = min(result, abs(bsum - asum));
        return ;
    }
    if(pos > n) return ;
    c[pos]=0;
    bt(depth, pos+1, c);
    c[pos]=1;
    bt(depth+1, pos+1, c);
    c[pos]=0;
    return ;
}

int main()
{   
    cin >> n;
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            scanf("%d", &s[i][j]);
        }
    }
    bt(0,1, c);
    printf("%d", result);
    return 0;
}

느낀점

첫 백트래킹 문제로 순열 조합을 출력하는 문제를 풀때 도대체 어떻게 이걸 구현하는거지? 하며 한참동안 머리아파했던 기억이 선명하다. 그래도 이제 기본적인 백트래킹 문제는 수월하게 해결할 수 있게 된것같아 뿌듯하다.

'알고리즘 문제풀이' 카테고리의 다른 글

[백준] 2156번 포도주 시식 c++  (0) 2021.08.01
[백준] 9663번 N-Queen C++  (0) 2021.08.01
[백준] 2580번 스도쿠 c++  (0) 2021.07.29
[백준] 11404번 플로이드 c++  (0) 2021.07.25
[백준] 11657번 타임머신 c++  (0) 2021.07.21

+ Recent posts