2660번 회장뽑기
문제
월드컵 축구의 응원을 위한 모임에서 회장을 선출하려고 한다. 이 모임은 만들어진지 얼마 되지 않았기 때문에 회원 사이에 서로 모르는 사람도 있지만, 몇 사람을 통하면 모두가 서로 알 수 있다. 각 회원은 다른 회원들과 가까운 정도에 따라 점수를 받게 된다.
예를 들어 어느 회원이 다른 모든 회원과 친구이면, 이 회원의 점수는 1점이다. 어느 회원의 점수가 2점이면, 다른 모든 회원이 친구이거나 친구의 친구임을 말한다. 또한 어느 회원의 점수가 3점이면, 다른 모든 회원이 친구이거나, 친구의 친구이거나, 친구의 친구의 친구임을 말한다.
4점, 5점 등은 같은 방법으로 정해진다. 각 회원의 점수를 정할 때 주의할 점은 어떤 두 회원이 친구사이이면서 동시에 친구의 친구사이이면, 이 두사람은 친구사이라고 본다.
회장은 회원들 중에서 점수가 가장 작은 사람이 된다. 회장의 점수와 회장이 될 수 있는 모든 사람을 찾는 프로그램을 작성하시오.
입력
입력의 첫째 줄에는 회원의 수가 있다. 단, 회원의 수는 50명을 넘지 않는다. 둘째 줄 이후로는 한 줄에 두 개의 회원번호가 있는데, 이것은 두 회원이 서로 친구임을 나타낸다. 회원번호는 1부터 회원의 수만큼 붙어 있다. 마지막 줄에는 -1이 두 개 들어있다.
출력
첫째 줄에는 회장 후보의 점수와 후보의 수를 출력하고, 두 번째 줄에는 회장 후보를 오름차순으로 모두 출력한다.
예제 입력
5
1 2
2 3
3 4
4 5
2 4
5 3
-1 -1
예제 출력
2 3
2 3 4
해결방법
모든 정점간의 연결 유무를 파악하는 All-to-All 문제이다
- n≦50
- 노드 간의 연결 여부 파악
- 직접 연결의 경우, 간접 연결의 경우(1), 간접 연결의 경우(2), …
- 모두 연결되어 있고 최소 점수대를 가지면 회장 후보
- 모든 경우를 파악해야 하므로 플로이드-와샬 알고리즘 사용
이 문제는 처음에 개념만 잘 세우면 되는 문제였다
직접 연결되어 있으면 dist[i][j] = 1 이다
만약 다른 정점 간의 간선이 없을 때 정점 k와 각각 연결되어 있다면
- dist[i][j] = dist[i][k] + dist[k][j]
일 것이다
밑에 코드는 최단 경로를 기준으로 회장 후보를 뽑는 코드인데 너무 더럽다...
// 모든 다른 회원과 친구로 연결되어 있는 경우
for(int i=1; i<=n; i++){
bool flag = true;
int max_ = -1;
for(int j=1; j<=n; j++){
if(i==j) continue;
if(dist[i][j] == INF) flag = false;
else max_ = max(max_,dist[i][j]);
}
if(flag) score.push_back(max_);
}
// 위의 경우에서 회장 후보만 필터링
auto c_score = *min_element(score.begin(), score.end());
for(int i=0; i<score.size(); i++){
if(score[i] == c_score){
candidate.push_back(i+1);
}
}
// 회장 후보의 점수, 회장 후보의 수, 회장 후보의 인덱스 출력
cout << c_score << " " << candidate.size() << "\n";
for(int i=0; i<candidate.size(); i++){
cout << candidate[i] << " ";
}
cout << "\n";
아래의 코드는 어느 블로그에서 본 코드인데 나중에 참고해야겠다….흫
int minScore = N;
vector<int> elected;
for(int i=1; i <= N; i++) {
int score = 0;
for(int j=1; j <= N; j++)
score = max(score, d[i][j]);
if(minScore > score)
{
minScore = score;
elected.clear();
}
if(minScore == score)
elected.push_back(i);
}
소스코드
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <bitset>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define MAX 51
#define INF 987654321
using namespace std;
int n;
int u,v;
int adj[MAX][MAX];
int dist[MAX][MAX];
vector<int> score;
vector<int> candidate;
void floyd(){
// 초기화
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(i==j) dist[i][j] = 0;
else if(adj[i][j] == 1) dist[i][j] = 1;
else dist[i][j] = INF;
}
}
// 최단 경로 갱신
for(int k=1; k<=n; k++){
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(i==j) continue;
if(i==k || j==k) continue;
if(dist[i][j] > dist[i][k] + dist[k][j]){
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
// 모든 다른 회원과 친구로 연결되어 있는 경우
for(int i=1; i<=n; i++){
bool flag = true;
int max_ = -1;
for(int j=1; j<=n; j++){
if(i==j) continue;
if(dist[i][j] == INF) flag = false;
else max_ = max(max_,dist[i][j]);
}
if(flag) score.push_back(max_);
}
// 위의 경우에서 회장 후보만 필터링
auto c_score = *min_element(score.begin(), score.end());
for(int i=0; i<score.size(); i++){
if(score[i] == c_score){
candidate.push_back(i+1);
}
}
// 회장 후보의 점수, 회장 후보의 수, 회장 후보의 인덱스 출력
cout << c_score << " " << candidate.size() << "\n";
for(int i=0; i<candidate.size(); i++){
cout << candidate[i] << " ";
}
cout << "\n";
}
int main(int argc, const char * argv[]) {
// cin,cout 속도향상
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
cin >> n;
while(true){
cin >> u >> v;
if(u==-1 && v==-1) break;
adj[u][v] = 1;
adj[v][u] = 1;
}
floyd();
}
'Algorithm > BOJ 문제풀이' 카테고리의 다른 글
[BFS] 7562번 나이트의 이동 (0) | 2018.12.13 |
---|---|
[Floyd] 9205번 맥주 마시면서 걸어가기 (0) | 2018.12.09 |
[Floyd] 1956번 운동 (0) | 2018.12.09 |
[Floyd] 2458번 키 순서 (0) | 2018.12.09 |
[Floyd] 1613번 역사 (0) | 2018.12.09 |