G. MST with Matching:
题目大意:
思路解析:
这里根据离散数学上的定理可知,最大匹配数等价于最小点覆盖, 最小点覆盖的定义是二分图中每个边至少一个端点在该点集中 的 最小点集。那么看到 n==20,我们可以想到我们是否可以枚举最小点覆盖的各种情况,然后基于这样的条件下找出当前情况下的最小生成树。
那么可以发现这样的时间复杂度为 2^n * n * n。是可以满足时间复杂度的。
代码实现:
import java.io.*;
import java.math.BigInteger;
import java.util.*;
public class Main {
static int inf = (int) 1e9;
static int mod = 998244353;
public static void main(String[] args) throws IOException {
int t = 1;
while (t > 0) {
solve();
t--;
}
w.flush();
w.close();
br.close();
}
static int n;
static int[][] g;
public static void solve() throws IOException {
n = f.nextInt(); int c = f.nextInt();
int[] cnt = new int[(1 << n)];
for (int i = 0; i < (1 << n); i++) {
int j = i;
int cur = 0;
while (j > 0){
if ((j & 1) == 1) cur++;
j >>= 1;
}
cnt[i] = cur;
}
g = new int[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
g[i][j] = f.nextInt();
if (g[i][j] == 0) g[i][j] = inf;
}
}
int ans = inf;
for (int i = 0; i < (1 << n); i++) {
int cur = prime_MST(i);
if (cur != inf) ans = Math.min(ans, cur + c * cnt[i]);
}
w.println(ans);
}
public static int prime_MST(int can){
int ans = 0;
int[] d = new int[n];
Arrays.fill(d, inf);
d[0] = 0;
boolean[] used = new boolean[n];
for (int i = 0; i < n; i++) {
int idx = -1;
for (int j = 0; j < n; j++) {
if (!used[j] && d[j] < inf && (idx == -1 || d[j] < d[idx]))
idx = j;
}
if (idx == -1) return inf;
used[idx] = true;
ans += d[idx];
for (int j = 0; j < n; j++) {
if (used[j]) continue;
if (((can >> j) & 1) == 0 && ((can >> idx) & 1) == 0) continue;
d[j] = Math.min(d[j], g[idx][j]);
}
}
return ans;
}
static PrintWriter w = new PrintWriter(new OutputStreamWriter(System.out));
static Input f = new Input(System.in);
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static class Input {
public BufferedReader reader;
public StringTokenizer tokenizer;
public Input(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public String nextLine() {
String str = null;
try {
str = reader.readLine();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
return str;
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public Double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}
}