最小生成树的扩展应用
例题:新的开始
【输入样例】
4
5
4
4
3
0 2 2 2
2 0 3 3
2 3 0 4
2 3 4 0
【输出样例】
9
————————————————————————————————————————————————————
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int INF = Integer.MAX_VALUE >> 1;
static int N = 310;
static int n;
static int[][] w = new int[N][N];
static int[] dist = new int[N];
static boolean[] st = new boolean[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
for (int i = 1; i <= n; i++) {
w[0][i] = sc.nextInt();
w[i][0] = w[0][i];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
w[i][j] = sc.nextInt();
}
}
System.out.println(prim());
}
private static int prim() {
Arrays.fill(dist, INF);
dist[0] = 0;
int res = 0;
for (int i = 0; i < n + 1; i++) {
int t = -1;
for (int j = 0; j <= n; j++) {
if (!st[j] && (t == -1 || dist[t] > dist[j])) {
t = j;
}
}
res += dist[t];
st[t] = true;
for (int j = 0; j <= n; j++) {
dist[j] = Math.min(dist[j], w[t][j]);
}
}
return res;
}
}
例题:北极通讯网络
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
static int INF = Integer.MAX_VALUE >> 1;
static int N = 510;
static int M = N * N / 2;
static int n;
static int k;
static int m;
static Edge[] e = new Edge[M];
static Pair[] q = new Pair[M];
static int[] p = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
k = sc.nextInt();
for (int i = 0; i < n; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
q[i] = new Pair(x, y);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
e[m++] = new Edge(i, j, get_dist(q[i], q[j]));
}
}
Arrays.sort(e, 0, m, new Comparator<Edge>() {
@Override
public int compare(Edge o1, Edge o2) {
if (o1.w <= o2.w) {
return -1;
} else {
return 1;
}
}
});
for (int i = 0; i < n; i++) {
p[i] = i;
}
int cnt = n;
double res = 0;
for (int i = 0; i < m; i++) {
if (cnt <= k) break;
int a = find(e[i].a);
int b = find(e[i].b);
double w = e[i].w;
if (a != b) {
p[a] = b;
cnt--;
res = w;
}
}
System.out.printf("%.2f\n", res);
}
private static int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
private static double get_dist(Pair a, Pair b) {
int dx = a.x - b.x;
int dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
}
class Pair{
int x;
int y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
}
class Edge{
int a;
int b;
double w;
public Edge(int a, int b, double w) {
this.a = a;
this.b = b;
this.w = w;
}
}
例题:346. 走廊泼水节
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
static int N = 6010;
static int n;
static Edge[] e = new Edge[N];
static int[] p = new int[N];
static int[] size = new int[N];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
while (T-- > 0) {
n = sc.nextInt();
for (int i = 0; i < n - 1; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int w = sc.nextInt();
e[i] = new Edge(a, b, w);
}
Arrays.sort(e, 0, n - 1, new Comparator<Edge>() {
@Override
public int compare(Edge o1, Edge o2) {
return o1.w - o2.w;
}
});
for (int i = 1; i <= n; i++) {
p[i] = i;
size[i] = 1;
}
int res = 0;
for (int i = 0; i < n - 1; i++) {
int a = find(e[i].a);
int b = find(e[i].b);
int w = e[i].w;
if (a != b) {
res += (size[a] * size[b] - 1) * (w + 1);
size[b] += size[a];
p[a] = b;
}
}
System.out.println(res);
}
}
private static int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
}
class Edge{
int a;
int b;
int w;
public Edge(int a, int b, int w) {
this.a = a;
this.b = b;
this.w = w;
}
}
例题:秘密的牛奶运输
【题目描述】
Farmer John 要把他的牛奶运输到各个销售点。运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点。 运输的总距离越小,运输的成本也就越低。低成本的运输是 Farmer John 所希望的。不过,他并不想让他的竞争对手知道他具体的运输方案,所以他希望采用费用第二小的运输方案而不是最小的。现在请你帮忙找到该运输方案。
【输入】
第一行是两个整数 N,M,表示顶点数和边数;
接下来 M行每行 3 个整数,x,y,z,表示一条路的两端 x,y 和距离 z。
【输出】
仅一行,输出第二小方案。
【输入样例】
4 4
1 2 100
2 4 200
2 3 250
3 4 100
【输出样例】
450
【提示】
数据范围:
对于全部数据,1≤N≤2000,1≤M≤20000,1≤z≤109 ,数据可能有重边。
——————————————————————————————————————————————————————
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
static int N = 510;
static int M = 10010;
static int n;
static int m;
static Edge[] edge = new Edge[M];
static int[] p = new int[N];
static int[][] dist = new int[N][N];
static int[] h = new int[N];
static int[] e = new int[N * 2];
static int[] w = new int[N * 2];
static int[] ne = new int[N * 2];
static int idx;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
Arrays.fill(h, -1);
for (int i = 0; i < m; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int w = sc.nextInt();
edge[i] = new Edge(a, b, w);
}
Arrays.sort(edge, 0, m, new Comparator<Edge>() {
@Override
public int compare(Edge o1, Edge o2) {
return o1.w - o2.w;
}
});
for (int i = 1; i <= n; i++) {
p[i] = i;
}
long sum = 0;
for (int i = 0; i < m; i++) {
int a = edge[i].a;
int b = edge[i].b;
int w = edge[i].w;
int pa = find(a);
int pb = find(b);
if (pa != pb) {
p[pa] = pb;
sum += w;
add(a, b, w);
add(b, a, w);
edge[i].f = true;
}
}
for (int i = 1; i <= n; i++) {
dfs(i, -1, 0, dist[i]);
}
long res = (long) 1e18;
for (int i = 0; i < m; i++) {
if (!edge[i].f) {
int a = edge[i].a;
int b = edge[i].b;
int w = edge[i].w;
if (w > dist[a][b]) {
res = Math.min(res, sum + w - dist[a][b]);
}
}
}
System.out.println(res);
}
private static void dfs(int u, int fa, int maxd, int[] d) {
d[u] = maxd;
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j != fa) {
dfs(j, u, Math.max(maxd, w[i]), d);
}
}
}
private static void add(int a, int b, int c) {
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
private static int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
}
class Edge{
int a;
int b;
int w;
boolean f = false;
public Edge(int a, int b, int w) {
this.a = a;
this.b = b;
this.w = w;
}
}