https://www.acmicpc.net/problem/10972
구현
- 수열의 순서를 생성하는 방법을 알아야만 풀 수 있다.
실제로 규칙을 찾기엔 굉장히 복잡한데, 암기하는게 맞는 것 같고,
CPP에는 이미 algorithm에 관련 함수가 구현되어있다.
next_permutation(v.begin(), v.end()
prev_permutation(v.begin(), v.end()
next 작동 방식은, 다음 수열이 있다면 true를 반환하고,
v에 저장된 1234라는 어떤 순서를 다음 수열인 1243으로 바꾸어준다.
v 내부의 원소들의 순서가 직접 바뀌게 되고,
바로 iterator로 출력하면 다음 수열이 된다.
문제점
1. 외우자..
https://guiyum.tistory.com/29
2. 그냥 DFS하려고 하면 안되는 이유가, 10000000개로, 1억을 넘어간다.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
vector<int> my_next_permutation(vector<int> vv, int n);
vector<int> v;
int N;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for (int i = 0; i < N; i++)
{
int num;
cin >> num;
v.push_back(num);
}
/*
if(next_permutation(v.begin(), v.end()))
{
for(int i=0;i<N;i++)
{
cout << v[i] << ' ';
}
}
else
{
cout << -1;
}
*/
v = my_next_permutation(v, N);
for (int i = 0; i < N; i++)
{
cout << v[i] << ' ';
}
return 0;
}
vector<int> my_next_permutation(vector<int> a, int n)
{
vector<int> vv = a;
int i = n - 1; // 인덱스는 0~n-1이기 때문.
while (i > 0 && vv[i - 1] >= vv[i]) // 5 4 3 2 1 이렇게 내림차순인걸 확인
{
i -= 1;
}
if (i <= 0)
{
// return false;
}
int j = n - 1;
while (vv[i - 1] >= vv[j]) // 내림차순 바로 이전 수보다 첫 큰 j를 찾기
{
j -= 1;
}
swap(vv[i - 1], vv[j]); // 그 둘을 swap하면 다음 순서가 됨
j = n - 1;
while (i < j)
{
swap(vv[i], vv[j]);
i += 1;
j -= 1;
}
return vv;
}
https://www.acmicpc.net/problem/10973
구현
- prev_permutation로 교체하면 된다.
- 실제 구현은 아래 참고
https://velog.io/@somyeong0623/%EB%B0%B1%EC%A4%80c-10973%EB%B2%88-%EC%9D%B4%EC%A0%84-%EC%88%9C%EC%97%B4
https://www.acmicpc.net/problem/10974
구현
- N이 주어졌을 때, N까지의 수로 가능한 수열들을 만드는 문제
- NM문제에서 N과 M이 동일한 수로 주어졌다는 것 외에
NM과 알고리즘상 다를게 전혀 없었다.
문제점
- 없.
int arr[9];
bool visited[9];
void DFS(int n)
{
if(n==N)
{
for(int i=0;i<N;i++)
{
cout << arr[i] << " ";
}
cout << "\n";
}
else
{
for(int i=1;i<=N;i++)
{
if(!visited[i])
{
visited[i] = true;
arr[n] = i;
DFS(n+1);
visited[i] = false;
}
}
}
}
https://www.acmicpc.net/problem/10819
구현
- NM문제와 비슷하다.
- 이번에는 결과에 arr[N]을 사용하는 것이 아니라,
vector를 사용하여 진행해보았다.
vector를 사용하므로 int n이라는 매개변수가 필요없었다.
문제점
1. 구현하기 헷갈렸다.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N;
int result = 0;
vector<int> v;
int arr[9];
bool visited[9] = {
0,
};
void DFS() // int n을 받지 않을거면 vector를 사용하면 편리
{
// 모든 원소를 다 채웠으면, 합을 확인, 최대면 갱신
if (v.size() == N)
{
int tmp = 0;
for (int i = 0; i < N - 1; i++)
{
tmp += abs(v[i + 1] - v[i]);
}
result = max(result, tmp);
return;
}
else
{
for (int i = 0; i < N; i++)
{
if (!visited[i])
{
visited[i] = true;
v.push_back(arr[i]);
DFS();
v.pop_back(); // vector를 사용한 dfs는 이렇게 한다.
visited[i] = false;
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for (int i = 0; i < N; i++)
{
cin >> arr[i];
}
DFS();
cout << result; //result를 여기에 적어야만 한다.
return 0;
}
https://www.acmicpc.net/problem/10971
구현
- NM 문제처럼 DFS를 돌려고 했고,
vector를 이용하여, DFS에 매개변수가 없도록 하였다.- v가 N개의 모든 도시를 방문했을 경우,
마지막 v[N-1]인덱스의 값에서 v[0]인덱스의 값으로 가는
거리를 더하여
해당 값이 최소인 것을 구하려고 하였다.- 이 과정에서 거리의 값이 0인 것을 처리하는 것이 미숙했는지,
예제는 맞는데 자꾸 틀렸다고 나왔다.
문제점
1. 거리 0에 주목하고, 내 아이디어대로 다시 구현해본다.
#include <iostream>
#include <vector>
using namespace std;
int N;
int w[10][10];
bool visited[10];
vector<int> v;
int result = 100000000;
void DFS()
{
if(v.size() == N)
{
//v.push_back(v[0]); // 순회해야 하므로 처음 값 추가
int tmp = 0;
cout << v[0] << " : ";
for(int i=0;i<N-1;i++)
{
cout << v[i+1] << " : ";
if(w[v[i]][v[i+1]] != 0) // 경로가 있다면,
{
tmp += w[v[i]][v[i+1]];
}
else
{
return; // 경로가 없다면, result를 갱신하지 않고 바로 return
}
}
// 순회해야 하므로
if(w[N-1][v[0]]!=0)
{
tmp+=w[v[N-1]][v[0]];
}
else
{
return;
}
cout << "= " << tmp << " \n ";
result = min(result, tmp);
return;
}
else
{
for(int i=0;i<N;i++)
{
if(!visited[i])
{
visited[i] = true;
v.push_back(i);
DFS();
v.pop_back();
visited[i] = false;
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
cin >> w[i][j];
}
}
DFS();
cout << result;
return 0;
}
https://www.acmicpc.net/problem/6603
구현
- 랜덤길이의 수열을 주고, 6개만 뽑으면 되는 문제,
오름차순이고, 순서가 중요했다.- NM문제에서 순서가 필요할 시 int num을 추가한 방법을 사용.
- vector는 입력값인 arr, DFS 답 저장용인 v를 사용하였다.
- v는 인덱스 값을 저장하는 용도이다.
문제점
1. % 올라가는 것 없이 내자마자 맞았다고 뜨는 경우는 처음봤다.
#include <iostream>
#include <vector>
using namespace std;
int N;
vector<int> arr;
vector<int> v;
bool visited[13] = {0, };
void DFS(int num)
{
if(v.size()==6)
{
for(int i=0;i<6;i++)
{
cout << arr[v[i]] << " ";
}
cout << "\n";
}
else
{
for(int i=num;i<N;i++)
{
if(!visited[i])
{
visited[i] = true;
v.push_back(i);
DFS(i);
v.pop_back();
visited[i] = false;
}
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
while(true)
{
cin >> N;
arr.clear();
if(N==0)
{
break;
}
for(int i=0;i<N;i++)
{
int num;
cin >> num;
arr.push_back(num);
}
DFS(0);
cout << "\n";
}
return 0;
}
https://www.acmicpc.net/problem/1759
구현
- 주어진 글자에서 글자 순서대로 비밀번호를 만든다.
- NM문제에 int n을 추가하여 순서를 고정시키는 유형이었고,
- 모음1, 자음2 이상이 있어야만 한다는 규칙을 위해서,
checkmoza라는 함수로 확인하고 true/false를 리턴하도록 하였다.- 추가 조건 외에는 NM문제+순서 문제라고 봐도 무방
문제점
1. 집중력이 떨어졌는지 이상한 실수를 했다.
for (int i = num; i < M; i++)
왜 M대신에 6을 적었던 걸까
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int N, M;
vector<int> v;
vector<char> arr;
bool visited[16];
// 모음 자음 조건이 맞는지 체크
bool checkmoza()
{
int mo = 0, ja = 0;
for (int i = 0; i < N; i++)
{
char ch = arr[v[i]];
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
{
mo++;
}
else
{
ja++;
}
}
if (mo >= 1 && ja >= 2)
{
return true;
}
else
{
return false;
}
}
void DFS(int num)
{
if (v.size() == N)
{
if (checkmoza())
{
for (int i = 0; i < N; i++)
{
cout << arr[v[i]];
}
cout << "\n";
}
else
{
return;
}
}
else
{
for (int i = num; i < M; i++) // M까지인데 6으로 써놨어서..
{
if (!visited[i])
{
visited[i] = true;
v.push_back(i);
DFS(i);
v.pop_back();
visited[i] = false;
}
}
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> N >> M;
for (int i = 0; i < M; i++)
{
char c;
cin >> c;
arr.push_back(c);
}
sort(arr.begin(), arr.end());
/*
for (auto i : arr)
{
cout << i << " ";
}
cout << "\n";
*/
DFS(0);
return 0;
}
https://www.acmicpc.net/problem/14501
구현
- 골드에서 똑같은 문제를 풀었었던 문제고,
똑같이 time을 사용하여 역순으로 ++ 했었는데,
그 방법을 사용하면 매우 복잡해진다.- 역순은 맞고, 아래의 식을 사용하는게 베스트.
d[i] = max(d[i+1], p[i] + d[i+t[i]])
문제점
1. 퇴사 문제 유형은 역순으로 하여 time을 쓸 생각을 하지 말고,
역순으로 d[i]를 구해나가는 것을 생각하자.
#include <iostream>
using namespace std;
// 초기화 및 선언
int t[16] = {
0,
};
int p[16] = {
0,
};
int d[16] = {
0,
};
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int N;
cin >> N;
// 입력값
for (int i = 1; i <= N; i++)
{
cin >> t[i];
cin >> p[i];
}
// 핵심
for (int i = N; i >= 1; i--)
{
if(i+t[i] > N+1) // 시간 상 할 수 없는 일이라면,
{
d[i] = d[i+1]; // 다음날의 일을 하도록 함.
}
else
{
d[i] = max(d[i+1], p[i] + d[i+t[i]]);
// 다음날의 일과, 다음시간의 일을 더한 값 중 큰 값을 현재 값으로 둠.
}
}
cout << d[1];
return 0;
}