백준 11014 컨닝2
https://www.acmicpc.net/problem/11014
이분 매칭(플로우) 문제입니다. 최근에 Dinic 을 정리했으니 Dinic으로 풀어보도록 하겠습니다.
이분매칭에서 Maximum independent set 의 개수는 total-maximum matching의 개수와 같음(Konig의 정리,시간끌기) 을 이용하여 시간끌기라는 문제를 푼 적이 있습니다. 이 문제도 이와 동일하게 maxmimum independent set의 크기를 구하는 문제입니다.
이제 남은 건 그래프 모델링 뿐입니다.
위 그림처럼 하얀색, 파란색으로 이분그래프를 나타낼 수 있습니다. 이렇게 나타내면, 하얀색 정점에 대하여 인접한 6개의 파란색 정점에는 학생이 동시에 앉을 수 없게 됩니다.
#include<bits/stdc++.h>
#define pb push_back
#define INF (int)1e9
using namespace std;
const int SZ=85;
char grid[SZ][SZ];
struct Edge{
int to,cap,rev;
Edge(int to, int cap, int rev){
this->to=to;
this->cap=cap;
this->rev=rev;
}
};
struct Dinic{
int n,src,dst;
vector<vector<Edge>> graph;
vector<int> crt;
vector<int> lv;
Dinic(int n, int src, int dst){
this->n=n;
this->src=src;
this->dst=dst;
graph.resize(n+5);
crt.resize(n+5);
lv.resize(n+5);
}
void push_edge(int a, int b, int capa){
graph[a].pb(Edge(b,capa,graph[b].size()));
graph[b].pb(Edge(a,0,graph[a].size()-1));
}
bool bfs(){
for(int i=0;i<n+5;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(nxt.cap<=0 || lv[nxt.to]) 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 ans=0;
while(bfs()){
for(int i=0;i<n+5;i++) crt[i]=0;
int f;
while((f=dfs(src,INF))>0){
ans+=f;
}
}
return ans;
}
};
#define myf(i,j) (i*m+j+1)
int main(void){
ios::sync_with_stdio(false); cin.tie(NULL);
int t; cin>>t;
while(t--){
int n,m; cin>>n>>m;
for(int i=0;i<n;i++) cin>>grid[i];
Dinic dn=Dinic(n*m,0,n*m+1);
int dx[6]={-1,-1,0,0,1,1};
int dy[6]={-1,1,-1,1,-1,1};
int tot=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(grid[i][j]=='.'){
tot++;
if(j%2==0) dn.push_edge(dn.src,myf(i,j),1);
else dn.push_edge(myf(i,j),dn.dst,1);
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<m;j+=2){
if(grid[i][j]=='x') continue;
for(int k=0;k<6;k++){
int nx=i+dx[k];
int ny=j+dy[k];
if(nx<0 || nx>=n) continue;
if(ny<0 || ny>=m) continue;
if(grid[nx][ny]=='x') continue;
dn.push_edge(myf(i,j),myf(nx,ny),1);
}
}
}
cout<<tot-dn.flow()<<'\n';
}
return 0;
}