백준 17135 캐슬 디펜스
캐슬 디펜스
이번 문제는 아기상어 문제를 풀고 조금더 어려운 문제를 풀어보고 싶어서 도전한 문제다.
날 너무 힘들게 했다. 너무 어려웠다..
문제분석
첫째, 0~n-1행까지는 맵이 나오고, n번째 행에는 궁수가 존재할수도, 존재하지 않을 수도 있다. 그중에 3곳에 궁수가 존재한다.
dfs, 브루트포스(재귀) 어떤걸로 구현해도 상관 없다. 성의 위치 중 3가지를 고르기만 하면 된다.
다만 브루트포스에서 주의할 점은, 1 2 3과 1 3 2는 같은경우이므로 중복제거를 꼭 해주어야한다.
둘째, 각 궁수가 위치하고 있는 자리에서 가장 가까운 적(여러 위치가 있다면, 가장 왼쪽)을 공격한다. 공격당한 적은 제외된다.
이 부분이 이 문제에서 가장 까다로운 부분이다. 각 궁수의 위치에서 최단거리 적을 발견했을 때 바로 제외하지 않고 한 라운드가 끝나고나서 모든 궁수가 적을 쏜 후에 적을 제외시켜줘야한다
셋째, 궁수가 쏠 수 있는 거리는 d로 한정되어있다
bfs탐색에서 d보다 dist가 클 때 continue하면 된다.
넷째, 한 라운드가 끝나면 모든 적이 한칸씩 내려온다.
이부분은 궁수가 한칸 올라간다고 처리해주면 굳이 모든 적을 밑칸으로 옮길 필요 없다.
문제풀이 후 든 생각
아직 실력이 너무 부족하다. 궁수를 세 곳에 위치시키고 bfs로 최단거리 탐색까지는 잘 생각해냈고 문제도 술술 풀린거 같았지만, 같은 적이 여러 궁수에게 공격당할 수 있다 조건 때문에 거의 이틀이나 고민했다. 당연히 최대값이니까 적이 공격당하면 바로 제외시킨 게 결정적인 패인이 되었다.
5 5 2
1 0 1 1 1
0 1 1 1 1
1 0 1 0 1
1 1 0 1 0
1 0 1 0 1
경우엔 내 코드에서는 15를 구했고,
정답은 14이다.
더 적을 경우가 존재하는 것이다.
사실 이 조건을 제외하고도, 내 논리를 코드로 구현하는게 많이 부족하다는 것을 깨달았다.
연습을 많이 해야겠다.
소스
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int ma[20][20];
int x_index[4]={-1,0,0};
int y_index[4]={0,-1,1};
int n,m,d;
bool where[20]={0};
tuple<int,int,int> bfs(int ar_x,int ar_y){
queue<pair<int,int>> q;
q.push(make_pair(ar_x,ar_y));
vector<tuple<int,int,int>> ans;
int dist[20][20]={0};
int cnt=0;
int visited[20][20]={0};
visited[ar_x][ar_y]=1;
while(!q.empty()){
int nx,ny;
tie(ar_x,ar_y)=q.front(); q.pop();
visited[ar_x][ar_y]=true;
if(cnt==0)
{
nx=ar_x+x_index[0];
ny=ar_y+y_index[0];
if(nx>=0&&nx<n&& ny>=0 && ny<m){
dist[nx][ny]=1;
if(ma[nx][ny]==1)
{
ans.push_back(make_tuple(dist[nx][ny],ny,nx));
}
q.push(make_pair(nx,ny));
}
cnt++;
}
else{
for(int i=0;i<3;i++)
{
nx=ar_x+x_index[i];
ny=ar_y+y_index[i];
if(nx>=0&&nx<n&& ny>=0 && ny<m){
dist[nx][ny]=dist[ar_x][ar_y]+1;
if(dist[nx][ny]>d || visited[nx][ny]==1)
continue;
if(ma[nx][ny]==1)
{
ans.push_back(make_tuple(dist[nx][ny],ny,nx));
}
q.push(make_pair(nx,ny));
}
}
}
}
if(ans.empty())
{
return make_tuple(-1,-1,-1);
}
sort(ans.begin(),ans.end());
return ans[0];
}
int cal(){
int ar_x;
int x,y,z;
int ans=0;
for(int i=n-1;i>=0;i--){// 행의 개수만큼 실행
ar_x=i+1;
vector<pair<int,int>> enemy;
for(int j=0;j<m;j++){
if(where[j]==true)
{
tie(z,y,x)=bfs(ar_x,j);
if(z==-1)
continue;
enemy.push_back(make_pair(x,y));
}
}
int e_x,e_y;
sort(enemy.begin(), enemy.end());
enemy.erase(unique(enemy.begin(),enemy.end()),enemy.end());
for(auto ene : enemy){
e_x=ene.first;
e_y=ene.second;
ma[e_x][e_y]=3;
ans++;
}
}
for(int i=0;i<n;i++){// 행의 개수만큼 실행
for(int j=0;j<m;j++){
if(ma[i][j]==2||ma[i][j]==3)
ma[i][j]=1;
}
}
return ans;
}
int go(int index, int person){ //궁수 명수
int ans=0;
if(person==3)
{
ans=cal();
return ans;
}
for(int i=index;i<m;i++)//열의개수만큼 3가지 경우 고름
{
if(where[i]==true)
{
continue;
}
where[i]=true;
ans=max(ans,go(i+1,person+1));
where[i]=false;
}
return ans;
}
int main(){
cin>>n>>m>>d;
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
cin>>ma[i][j];
}
cout<<go(0, 0)<<'\n';
}
댓글남기기