[풀이]백준 풀이(X/16924 등 )
문제풀이
연결 요소의 개수(16924, BFS/DFS)
연결성분(connected component)란?
- 나누어진 각각의 그래프
- 서로 연결되어 있는 여러 개의 고립된 부분 그래프 각각을 연결 성분이라 부른다.
- 그룹화하는 문제랑 비슷한 것으로 보인다.
연결 성분을 찾는 방법
- BFS, DFS 모두 이용가능하다.
임의의 방문하지 않은 정점에서 BFS를 실행한다를 반복한다.
회고
-
20분도 안걸렸다. 이제 이런 기본문제는 풀 만하니 구현력을 키워보도록 하자.
-
인덱스를 잘 생각하자 ㅎㅎ… 자주 실수하네
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int n, m, u ,v, Answer=0;
bool visited[1001];
int check[1000][1000];
bool isInside(int y){
if(y<n && y>=0) return true;
else return false;
}
void bfs(int s) {
queue<int> q;
q.push(s);
visited[s] = true;
while(!q.empty()){
int x = q.front();
q.pop();
for(int y=0; y<n; y++){
//간 적 없고 인접행렬 범위 이내이면 BFS
if(check[x][y]==1 && isInside(y)){
visited[y] = true;
//연결 끊어버려
check[x][y]= check[y][x] = 0;
q.push(y);
}
}
}
}
int main() {
cin >> n >> m;
//init
for(int i=0; i<1000; i++){
visited[i] = false;
for(int j=0; j<1000; j++){
check[i][j] = 0;
}
}
//인접행렬 제작
for(int i=0; i<m; i++){
cin >> u >> v;
check[u-1][v-1] = check[v-1][u-1] = 1;
}
for(int i=0; i<n; i++){
if(!visited[i]){
bfs(i);
Answer++;
}
}
cout << Answer;
}
순열사이클(10451, BFS/DFS)
-
1부터 N까지의 수열이 주어지고 이를 무작위로 변경한 수열이 주어진다.
-
이 두 수열의 사이에 존재하는 순열 사이클을 찾으시오.
-
사이클을 찾아야 하니 알고리즘이 약간 다르다.
순열사이클의 조건
-
2개 이상의 노드가 사이클을 이루는 것
-
자기 자신이 혼자 사이클 인 것
회고
- 인접행렬이 필요없다.
- 처음에는 사이클이 걸려있어서 복잡하게 생각했는데 엄청 간단한 문제였던 것 같다.
- 정확한 원리는 잘 모르겠지만 ^^,, bfs를 돌면 무조건 사이클이 발생하는 것이 순열사이클 인 것 같다.
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int test_case,n, m, Answer=0;
bool visited[1001];
int check[1000][1000];
bool isInside(int y){
if(y<n && y>=0) return true;
else return false;
}
void bfs(int s) {
//조건 1. 2개 이상의 노드가 사이클을 이루는 것
queue<int> q;
q.push(s);
visited[s] = true;
while(!q.empty()){
int x = q.front();
q.pop();
for(int y=0; y<n; y++){
if(check[x][y]==1 && isInside(y))
{
visited[y] = true;
check[x][y]= check[y][x] = 0;
//이 상황에서 시간초과가 발생했던 것 같다.
if(x==y)
{
break;
}
else
{
q.push(y);
}
}
}
}
//어짜피 while이 끝났다 = 사이클을 찾았다.
}
int main() {
cin >>test_case;
for(int a=0; a<test_case; a++){
cin >> n;
//init
for(int i=0; i<n; i++){
visited[i] = false;
for(int j=0; j<n; j++){
check[i][j] = 0;
}
}
//인접행렬 x
for(int i=0; i<n; i++){
cin >> m;
check[i][m-1] = 1;
}
for(int i=0; i<n; i++){
if(!visited[i]){
bfs(i);
Answer++;
}
}
cout << Answer << endl;
Answer = 0;
}
}
[RE]리모컨(1107, 시뮬레이션)
- 리모컨의 숫자버튼 일부가 망가진 상태
- 리모컨은 숫자 0~9, +, - 버튼이 있다.
- 채널은 무한대이다.(양수로만)
- N채널로 이동하기 위한 최소 횟수는?
최소 횟수라는 말이 문제다…
생각
- 가려는 채널 - 현재채널 값을 계산한다.
- 차이가 2이하면 ++ or –를 입력
- 그 이상이면 자릿수 차이가 적은 것을 기준으로 가장 가까운 숫자를 고른다.
- 구현도중 시간초과로 실패처리
회고
- 절대값처리, 자릿수로 쪼개기 등은 잘 생각한 것 같다.
- 그러나 문제를 너무 어렵게 접근해서 못푼 것 같음.
풀이
변수
num_1= 도착지와 시작위치의 차이값이다 (abs(num_1))broken[12]= 부서진 버튼을 구분하는 배열이다.- length = check(i);
N의 범위가 50만까지이므로 모든 경우를 다 해본다. (고장난 버튼을 고려하여 100,000..?? 왜?)
for(int i=0; i<1000001; i++){
length = check(i);
if(length)
{
int k = n-i;
if(k<0) k *= (-1);
if(k<mini)
{
mini = k;
l = length;
}
}
}
- k = 100에서 +,-버튼으로 원하는 채널까지 이동하는 경우의 수
- x(고장난 버튼때문에 원하는 채널에서 가장 가까운 수까지 버튼을 누른 수) + y(나머지 +,-로 이동한 수)
1/2를 비교하여 min값을 출력한다.
#include <iostream>
#include <queue>
#include <algorithm>
#include <math.h>
#define INF 987654321
using namespace std;
int n, m, Answer=0, mini = INF, length, l;
bool broken[12];
int channel[6];
//해당 수로 이동이 가능한지를 판별
int check(int k){
int length = 0;
if (k==0) return broken[0] ? 0 : 1;
//자릿수별로 계산
while(k)
{
length++;
if(broken[k%10]) return 0;
k/=10;
}
return length;
}
int main() {
cin >> n >> m;
int num_1 = n - 100;
if(num_1 <0) num_1 *= (-1);
for(int i=0; i<m; i++){
int temp;
cin >> temp;
//broken 0~9 숫자, 10 +, 11 -
broken[temp] = true;
}
for(int i=0; i<1000001; i++){
length = check(i);
if(length)
{
int k = n-i;
if(k<0) k *= (-1);
if(k<mini)
{
mini = k;
l = length;
}
}
}
int num_2 = mini + l;//x+y
cout << min(num_1, num_2);
}
OX퀴즈 (EZ, 8958)
자꾸 string to char배열을 검색하게 되어서 저장용으로 적어놓는 문제
string s;
char ox[80];
getline(cin, s);
strcpy(ox,s.c_str());
역소팅
#include <functional>
sort(afterSort.begin(), afterSort.end(), greater<int>());
댓글남기기