programmers.co.kr/learn/courses/30/lessons/42898
정답: 201009
참고 동적계획법에서 재귀가 아니라 이중for문을 사용해야 해결이 쉬워진다.
참고링크 :
www.youtube.com/watch?v=6NCae9uz5Ss
#include <string>
#include <vector>
#include<iostream>
using namespace std;
void Print(vector<vector<int>> path){
for(int i=0;i<path.size();i++){
for(int j=0;j<path[i].size();j++){
cout<<path[i][j]<<",";
}
cout<<endl;
}
cout<<endl;
}
long long Mod=1000000007;
int solution(int m, int n, vector<vector<int>> puddles) {
int answer = 0;
vector<int>tmpMap(m,0);
vector<vector<int>>map(n,tmpMap);
for(int i=0;i<puddles.size();i++){
for(int j=0;j<puddles[i].size();j++){
puddles[i][j]-=1;
}
}
for(int i=0;i<puddles.size();i++){
map[puddles[i][1]][puddles[i][0]]=-1;
}
map[0][0]=1;
map[n-1][m-1]=0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(map[i][j]==-1){
map[i][j]=0;
continue;
}
if(i!=0){
map[i][j]+=map[i-1][j]%Mod;
}
if(j!=0){
map[i][j]+=map[i][j-1]%Mod;
}
//map[i][j]=map[index0][j]+map[i][index1];
// Print(map);
}
}
// Print(map);
// long long answered=func(n-1,m-1,map);
answer=map[n-1][m-1]%Mod;
// cout<<answer;
return answer;
}
먼저 우리가 지나갈 MAP을 만들어준다.
vector<int>tmpMap(m,0);
vector<vector<int>>map(n,tmpMap);
그러면 NxM 행렬의 map의 경로가 나올것이다.
다음은 지날수 없는 장애물을 map에 설정해준다.
for(int i=0;i<puddles.size();i++){
for(int j=0;j<puddles[i].size();j++){
puddles[i][j]-=1;
}
}
for(int i=0;i<puddles.size();i++){
map[puddles[i][1]][puddles[i][0]]=-1;
}
-1은 현재 갈수없는 곳으로 지정된값이다.
그렇다면 이제 맵이 전체적으로 완성되었으니 동적계획법을 이용하여 경로를 찾아보자
맨처음 우리는 0,0에서 시작하므로 1을 입력해준다 그리고 마지막 도착지점은 혹시 장애물이 지정되어 있을수도 있으므로 미리 0으로 지정해둔다.
map[0][0]=1;
map[n-1][m-1]=0;
여기서 돌아가는 원리는 하나하나 따져보자
1,0,0,0,
0,-1,0,0,
0,0,0,0,
위의 같이 생긴 맵이라고 가정하자
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(map[i][j]==-1){
map[i][j]=0;
continue;
}
if(i!=0){
map[i][j]+=map[i-1][j]%Mod;
}
if(j!=0){
map[i][j]+=map[i][j-1]%Mod;
}
//map[i][j]=map[index0][j]+map[i][index1];
// Print(map);
}
}
처음엔 (0,0)은 이 두조건에 걸리므로 패스하고 다음 으로 넘어간다.
if(i!=0),if(j!=0)
그다음 (0,1)로 돌아간다.
이 조건에 걸리게 되어 현재
map[0][1]+=map[0][1-1]; 이된다.
if(j!=0){
map[i][j]+=map[i][j-1]%Mod;
}
그렇게 되면 아래와 같은 형태가 된다. 즉 오른쪽으로 한칸 이동하고 그 경로를 누적하여 기억하는것이다.
1,1,0,0,
0,-1,0,0,
0,0,0,0,
여기선 j가 끝까지 가는동안 i는 계속 0이므로 이전 j값과 다음 이동 j값으로 누적한다 그러면
아래와 같이 될것이다
1,1,1,1,
0,-1,0,0,
0,0,0,0,
. 이제 j가 끝나고 다시 i값이 증가한다. 이때 i는 0이 아니므로
아래의 조건에 만족한다 j는 초기화 되서 0이므로 j의 위의 조건에 부합하여 패스 된다.
if(i!=0){
map[i][j]+=map[i-1][j]%Mod;
}
아래와 같은 결과가 나온다.
1,1,1,1,
1,-1,0,0,
0,0,0,0,
그렇다면 i값은 1로 고정되어 있는 상태에서 다시 j값이 증가하면서 아래의 조건이 만족한다.
if(i!=0){
map[i][j]+=map[i-1][j]%Mod;
}
if(j!=0){
map[i][j]+=map[i][j-1]%Mod;
}
원래는 위의 조건이 맞아야하지만 장애물 -1이 있으므로
이 조건이 들어가게 된다.
continue에 의해서 j값은 증가하지만 아래의 조건은 패스하게 된다.
if(map[i][j]==-1){
map[i][j]=0;
continue;
}
패스 했다는거는 더이상 값에 영향을 주지 않기위해 0으로 바꾸엇다.
그러면 아래와 같다.
1,1,1,1,
1,0,1,0,
0,0,0,0,
이상태에서 다음 j값을 증가시키는데 이 두조건이 모두 해당된다.
현재 i=1,j=3 이므로
if(i!=0){
map[i][j]+=map[i-1][j]%Mod;
}
if(j!=0){
map[i][j]+=map[i][j-1]%Mod;
}
map[0][3],map[1][2]의 값을 map[1][3] 에게 누적해준다
그러면
1,1,1,1,
1,0,1,2,
0,0,0,0,
이러한 결과가 누적된다.
다음엔 마찬가지로 반복하면
1,1,1,1,
1,0,1,2,
1,1,2,4,
이상태의 결과가 나오며 마지막 지정 값이 4가지의 경우로 길을 찾을수 있다는것을 알게된다.
마지막에 배열의 크기가 클수 있으므로 조건에서 1,000,000,007 나머지를 계산해준다.
==========================================================================
재귀로 시도했으나 효율성 문제로 인해 안됨
그래서 이중for문을 사용한 DP를 이용해야하는듯하다.
아래는 깊이우선 탐색과 dp 재귀로 풀었을떄 방식이다.
일단 효율문제 제외하고 정확성 문제는 다 맞는듯하다.
정확성 8번도 시간초과인걸로 봐서 효율성 문제인듯
#include <string>
#include <vector>
#include<iostream>
#include<deque>
using namespace std;
long nor=1000000007;
deque<int>dq;
long long anwerdd;
void Print(vector<vector<int>> path){
for(int i=0;i<path.size();i++){
for(int j=0;j<path[i].size();j++){
cout<<path[i][j]<<",";
}
cout<<endl;
}
cout<<endl;
}
long long func( vector<vector<int>> path,int m,int n,long rightIndex,long downIndex){
if(rightIndex>m-2&&downIndex>n-2){
anwerdd++;
}
if(path[downIndex][rightIndex]==1){
return 0;
}
path[downIndex][rightIndex]=2;
// Print(path);
//
if(rightIndex<m-1){
// path[downIndex][rightIndex]=2;
func(path,m,n,(rightIndex+1),downIndex);//rigt
}
if(downIndex<n-1){
// path[downIndex][rightIndex]=2;
func(path,m,n,rightIndex,(downIndex+1));//down
}
return anwerdd%1000000007;
}
int solution(int m, int n, vector<vector<int>> puddles) {
int answer = 0;
vector<vector<int>> lake;
vector<int>tmps(m,0);
vector<vector<int>> path(n,tmps);
for(int i=0;i<puddles.size();i++){
for(int j=0;j<puddles[i].size();j++){
puddles[i][j]-=1;
}
}
//Print(puddles);
for(int i=0;i<puddles.size();i++){
if(puddles[i][0]<m&&puddles[i][1]<n){
path[puddles[i][1]][puddles[i][0]]=1;
}
}
path[0][0]=0;
path[n-1][m-1]=0;
long long answered=func(path,m,n,0,0);
answer=answered;
return answer%nor;
}
기존에는 깊이 우선 탐색 이용했으나 이번엔
개선 된 DP 이용 상황 현재 테스트 5를보면 이전엔 18초 걸리던게 9초 줄임
#include <string>
#include <vector>
#include<iostream>
using namespace std;
void Print(vector<vector<int>> path){
for(int i=0;i<path.size();i++){
for(int j=0;j<path[i].size();j++){
cout<<path[i][j]<<",";
}
cout<<endl;
}
cout<<endl;
}
long long Mod=1000000007;
long long func(int n,int m,vector<vector<int>>map){
if(map[n][m]==-1){
return 0;
}
if(m<=0&&n<=0){
return 1;
}
// long right=0;
// long down=0;
// if(m>0){
// right=func(n,m-1,map)%Mod;
// }
// if(n>0){
// down=func(n-1, m,map)%Mod;
// }
return (((m>0)?func(n,m-1,map):0)+((n>0)?func(n-1, m,map):0))%Mod;//right+down; //func(n,m-1,map)%Mod+func(n-1, m,map)%Mod;
}
int solution(int m, int n, vector<vector<int>> puddles) {
int answer = 0;
vector<int>tmpMap(m,0);
vector<vector<int>>map(n,tmpMap);
for(int i=0;i<puddles.size();i++){
for(int j=0;j<puddles[i].size();j++){
puddles[i][j]-=1;
}
}
for(int i=0;i<puddles.size();i++){
map[puddles[i][1]][puddles[i][0]]=-1;
}
map[0][0]=0;
map[n-1][m-1]=0;
// Print(map);
long long answered=func(n-1,m-1,map);
answer=answered;
return answer;
}