백준 9525 룩 배치하기
https://www.acmicpc.net/problem/9525
이분매칭 문제입니다. 체스판에 폰을 하나 추가할 때 마다 놓을 수 있는 룩의 개수가 하나 증가합니다. 이를 이용하면 이분매칭 모델링을 할 수 있습니다.
예제를 모델링한 사진입니다. 룩에 의해서 생기는 가로선을 왼쪽으로, 세로선을 오른쪽으로 하는 이분 그래프를 모델링 할 수 있습니다. 가로선과 세로선이 만나는 경우에는 두 선분 중 하나만을 선택해야 하므로 간선을 이어주면 됩니다.
#include<bits/stdc++.h>
#define pb push_back
#define INF (int)1e9+5
using namespace std;
const int SZ=105;
char chess[SZ][SZ];
int row[SZ][SZ];
int col[SZ][SZ];
struct Dinic{
struct Edge{
int to,rev,cap;
Edge(int to, int rev, int cap):to(to),rev(rev),cap(cap){
}
};
int n,m,src,dst;
vector<vector<Edge>> graph;
vector<int> crt;
vector<int> lv;
Dinic(int n, int m, int src, int dst):n(n),m(m),src(src),dst(dst){
graph.resize(n+m+5);
crt.resize(n+m+5);
lv.resize(n+m+5);
}
void push_edge(int a, int b, int capa){
graph[a].pb(Edge(b,graph[b].size(),capa));
graph[b].pb(Edge(a,graph[a].size()-1,0));
}
bool bfs(){
for(int i=0;i<=n+m+1;i++) lv[i]=0;
queue<int> q;
q.push(src); lv[src]=1;
while(!q.empty()){
int f=q.front(); q.pop();
for(auto nxt:graph[f]){
if(lv[nxt.to] || nxt.cap<=0) continue;
q.push(nxt.to); lv[nxt.to]=lv[f]+1;
}
}
return lv[dst]!=0;
}
int dfs(int x, int mnc){
if(x==dst) return mnc;
for(int &i=crt[x];i<(int)graph[x].size();i++){
auto &e=graph[x][i];
if(lv[x]>=lv[e.to] || e.cap<=0) continue;
int f=dfs(e.to,min(mnc,e.cap));
if(f>0){
e.cap-=f;
graph[e.to][e.rev].cap+=f;
return f;
}
}
return 0;
}
int flow(){
int res=0;
while(bfs()){
for(int i=0;i<=n+m+1;i++) crt[i]=0;
int f;
while((f=dfs(src,INF))>0){
res+=f;
}
}
return res;
}
};
void go_left(int x, int y, int n, int c){
for(int i=y;i<n;i++){
if(chess[x][i]=='X') return;
row[x][i]=c;
}
}
void go_down(int x, int y, int n, int c){
for(int i=x;i<n;i++){
if(chess[i][y]=='X') return;
col[i][y]=c;
}
}
int main(void){
ios_base::sync_with_stdio(false); cin.tie(NULL);
int n; cin>>n;
for(int i=0;i<n;i++) cin>>chess[i];
int lft=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(chess[i][j]=='X' || row[i][j]) continue;
go_left(i,j,n,++lft);
}
}
int rht=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(chess[j][i]=='X' || col[j][i]) continue;
go_down(j,i,n,++rht);
}
}
Dinic dn=Dinic(lft,rht,0,lft+rht+1);
for(int i=1;i<=lft;i++) dn.push_edge(0,i,1);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(chess[i][j]=='X') continue;
dn.push_edge(row[i][j],lft+col[i][j],1);
}
}
for(int i=lft+1;i<=lft+rht;i++) dn.push_edge(i,lft+rht+1,1);
cout<<dn.flow();
return 0;
}