[Baekjoon,2570]비숍2

1 분 소요

해결

종만북의 BISHOP문제와 거의 동일하며 풀이 또한 비슷하다.

비숍이 대각선으로만 이동할 수 있는데 이는 문제에서 주어진 맵에서 특정한 비숍이 있으면 그 비숍을 기준으로 오른쪽 아래 대각선(rd), 왼쪽 아래 대각선(ld) 방향으로는 비숍을 둘 수 없다는 것을 알 수 있다.

대각선 방향으로 연속한 빈 칸들을 묶어버리면 ld 기준으로 rd를 선택하는 이분매칭 문제가 된다.
즉, rd 그룹과 ld 그룹으로 나누어 같은 빈 칸을 공유하면 간선으로 이어 최대 유량을 찾으면 된다.

그룹을 나누는 것은 같은 반복적으로 그룹내에 속한 빈 칸들에 같은 번호를 부여하는 식으로 구현하였다.
이후 모든 정점을 돌아보며 빈 칸인 경우 해당 정점의 ld에서 rd로 가는 간선을 연결하였다.
이 다음에는 이분 매칭에서 최대유량을 구하는 방법으로 답을 얻었다.

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;

const int MAX=101;
// 왼쪽 아래, 오른쪽 아래 대각선
const int dx[2]={-1,1};
const int dy[2]={ 1,1};

// A그룹과 B그룹 각각의 크기
int n,m;
// true: 빈 칸, fales: 장애물
vector<vector<bool> > canPlace;
vector<vector<int> > adj;
vector<bool> visited;
vector<int> bMatch;
int id[2][MAX][MAX];

bool dfs(int a)
{
    if(visited[a]) return false;
    visited[a]=true;
    for(int i=0;i<adj[a].size();++i)
    {
        int b=adj[a][i];
        if(bMatch[b]==-1 || dfs(bMatch[b]))
        {
            bMatch[b]=a;
            return true;
        }
    }
    return false;
}

int bipartiteMatch()
{
    bMatch=vector<int>(m,-1);
    int ret=0;
    for(int start=0;start<n;++start)
    {
        visited=vector<bool>(n,false);
        if(dfs(start))
            ++ret;
    }
    return ret;
}

int placeBishop()
{
    int len=canPlace.size();
    int count[2]={0,0};
    memset(id,-1,sizeof(id));
    
    for(int dir=0;dir<2;++dir)
        for(int y=0;y<len;++y)
            for(int x=0;x<len;++x)
                if(canPlace[y][x] && id[dir][y][x]==-1)
                {
                    int cy=y, cx=x;
                    while(0<=cy && cy<len &&
                          0<=cx && cx<len && 
                          canPlace[cy][cx])
                    {
                        id[dir][cy][cx]=count[dir];
                        cy+=dy[dir];
                        cx+=dx[dir];
                    }
                    count[dir]++;
                }
    
    n=count[0];
    m=count[1];
    adj.resize(n+1);
    for(int y=0;y<len;++y)
        for(int x=0;x<len;++x)
            if(canPlace[y][x])
                adj[id[0][y][x]].push_back(id[1][y][x]);
    
    return bipartiteMatch();
}

int main()
{
    int size;
    cin>>size;
    canPlace=vector<vector<bool> >(size,vector<bool>(size,true));
    
    int blockNum;
    cin>>blockNum;
    for(int i=0;i<blockNum;++i)
    {
        int y,x;
        cin>>y>>x;
        --y; --x;
        canPlace[y][x]=false;
    }
    
    cout<<placeBishop()<<endl;
    return 0;
}

댓글남기기