반응형
문제 요약
노드 갯수 N과 간선 갯수 M이 주어진다. 그리고 각 정점의 차수 제한 $b_i$가 주어진다.
차수 제한을 만족하는 스패닝트리 중에서 그 비용이 가장 작은 스패닝 트리를 출력하시오. 차수 제한을 만족하는 스패닝트리가 없다면 NO를 출력하라.
N은 최대 10, M은 최대 27이다.
풀이
일단 최대 입력으로 들어왔을 때, 간선을 고르는 경우의 수는 $\binom{27}{9}$로 500만이 조금 안된다.
여기에다가 $M$을 곱해도 시간 내에 들어온다. (스패닝 트리가 되려면 간선을 N-1개 골라야 한다.)
즉, 간선을 고르고 스패닝 트리인지 확인하기 위해서 BFS나 DFS를 해도 시간 내에 충분히 돈다.
BFS나 DFS는 $O(N+M)$이다.
#include<bits/stdc++.h>
using namespace std;
struct Edge {
int u, v, w;
};
vector<vector<int>> G(15);
Edge a[30];
int N, M;
int b[15];
int deg[15];
int main() {
cin.tie(nullptr); ios::sync_with_stdio(false);
cin >> N >> M;
for(int i=1;i<=N;++i) cin >> b[i];
for(int i=0;i<M;++i) cin >> a[i].u >> a[i].v >> a[i].w;
if(M < N - 1) {
cout << "NO" << '\n';
return 0;
}
vector<int> v(M, 0);
for(int i=0;i<N-1;++i) v[i] = 1;
int ans = 1e9;
vector<int> ans_v;
do {
memset(deg, 0, sizeof(deg));
for(int i=1;i<=N;++i) G[i].clear();
int sum = 0;
for(int i=0;i<M;++i) {
if(!v[i]) continue;
int u = a[i].u;
int v = a[i].v;
int w = a[i].w;
deg[u]++; deg[v]++;
G[u].push_back(v); G[v].push_back(u);
sum += w;
}
bool valid = true;
for(int i=1;i<=N;++i) valid &= deg[i] <= b[i];
if(!valid) continue;
queue<int> q;
bool vis[15]; memset(vis, false, sizeof(vis));
vis[1] = true; q.push(1);
int cnt = 0;
while(!q.empty()) {
int cur = q.front();
q.pop();
++cnt;
for(int v : G[cur]) {
if(vis[v]) continue;
vis[v] = true;
q.push(v);
}
}
if(cnt == N) {
if(ans > sum) {
ans_v = v;
ans = sum;
}
}
} while(prev_permutation(v.begin(), v.end()));
if(ans == 1e9) cout << "NO" << '\n';
else {
cout << "YES" << '\n';
for(int i=0;i<M;++i) if(ans_v[i]) cout << a[i].u << ' ' << a[i].v << '\n';
}
return 0;
}
반응형
'Problem Solving > 문제풀이' 카테고리의 다른 글
백준 20940번 시철이가 사랑한 수식 (0) | 2021.03.02 |
---|---|
백준 20938번 반짝반짝 (0) | 2021.03.02 |
백준 20926번 얼음 미로 (0) | 2021.02.27 |
백준 20925번 메이플스토리 (0) | 2021.02.27 |
백준 20924번 트리의 기둥과 가지 (0) | 2021.02.27 |