最小生成树
例题:最短网络
对称矩阵—无向边
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int INF = Integer.MAX_VALUE >> 1;
static int N = 110;
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++) {
for (int j = 1; j <= n; j++) {
w[i][j] = sc.nextInt();
}
}
System.out.println(prim());
}
private static int prim() {
int res = 0;
Arrays.fill(dist, INF);
dist[1] = 0;
for (int i = 0; i < n; i++) {
int t = -1;
for (int j = 1; j <= n; j++) {
if (!st[j] && (t == -1 || dist[t] > dist[j])) {
t = j;
}
}
res += dist[t];
st[t] = true;
for (int j = 1; j <= n; j++) {
dist[j] = Math.min(dist[j], w[t][j]);
}
}
return res;
}
}
例题:局域网(net)
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N = 110;
static int M = 210;
static int n;
static int m;
static int[] p= new int[N];
static Edge[] e = new Edge[M];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++) {
p[i] = i;
}
for (int i = 0; i < m; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int w = sc.nextInt();
e[i] = new Edge(a, b, w);
}
Arrays.sort(e, 0, m, (o1, o2) -> o1.w - o2.w);
int res = 0;
for (int i = 0; i < m; i++) {
int a = find(e[i].a);
int b = find(e[i].b);
int w = e[i].w;
if (a != b) {
p[a] = b;
}else {
res += w;
}
}
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;
}
}
例题:繁忙的都市(city)
【输入样例】
4 5
1 2 3
1 4 5
2 4 7
2 3 6
3 4 8
【输出样例】
3 6
————————————————————————————————————————————————————
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N = 310;
static int M = 10010;
static int n;
static int m;
static int[] p= new int[N];
static Edge[] e = new Edge[M];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++) {
p[i] = i;
}
for (int i = 0; i < m; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
int w = sc.nextInt();
e[i] = new Edge(a, b, w);
}
Arrays.sort(e, 0, m, (o1, o2) -> o1.w - o2.w);
int res = 0;
for (int i = 0; i < m; i++) {
int a = find(e[i].a);
int b = find(e[i].b);
int w = e[i].w;
if (a != b) {
p[a] = b;
res = w;
}
}
System.out.println(n - 1 + " " + 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;
}
}
例题:联络员(liaison)
【题目描述】
Tyvj已经一岁了,网站也由最初的几个用户增加到了上万个用户,随着Tyvj网站的逐步壮大,管理员的数目也越来越多,现在你身为Tyvj管理层的联络员,希望你找到一些通信渠道,使得管理员两两都可以联络(直接或者是间接都可以)。Tyvj是一个公益性的网站,没有过多的利润,所以你要尽可能的使费用少才可以。
目前你已经知道,Tyvj的通信渠道分为两大类,一类是必选通信渠道,无论价格多少,你都需要把所有的都选择上;还有一类是选择性的通信渠道,你可以从中挑选一些作为最终管理员联络的通信渠道。数据保证给出的通行渠道可以让所有的管理员联通。
【输入】
第一行n,m表示Tyvj一共有n个管理员,有m个通信渠道;
第二行到m+1行,每行四个非负整数,p,u,v,w 当p=1时,表示这个通信渠道为必选通信渠道;当p=2时,表示这个通信渠道为选择性通信渠道;u,v,w表示本条信息描述的是u,v管理员之间的通信渠道,u可以收到v的信息,v也可以收到u的信息,w表示费用。
【输出】
最小的通信费用。
【输入样例】
5 6
1 1 2 1
1 2 3 1
1 3 4 1
1 4 1 1
2 2 5 10
2 2 5 5
【输出样例】
9
【提示】
【样例解释】
1-2-3-4-1存在四个必选渠道,形成一个环,互相可以到达。需要让所有管理员联通,需要联通2号和5号管理员,选择费用为5的渠道,所以总的费用为9。
【注意】
U,v之间可能存在多条通信渠道,你的程序应该累加所有u,v之间的必选通行渠道
【数据范围】
对于30%的数据,n≤10,m≤100;
对于50%的数据, n≤200,m≤1000
对于100%的数据,n≤2000,m≤10000
————————————————————————————————————————————————————
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static int N = 2010;
static int M = 10010;
static int n;
static int m;
static int[] p= new int[N];
static Edge[] e = new Edge[M];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1; i <= n; i++) {
p[i] = i;
}
int res = 0, k = 0;
for (int i = 0; i < m; i++) {
int t = sc.nextInt();
int a = sc.nextInt();
int b = sc.nextInt();
int w = sc.nextInt();
if (t == 1) {
res += w;
p[find(a)] = find(b);
}else {
e[k++] = new Edge(a, b, w);
}
}
Arrays.sort(e, 0, k, (o1, o2) -> o1.w - o2.w);
for (int i = 0; i < k; i++) {
int a = find(e[i].a);
int b = find(e[i].b);
int w = e[i].w;
if (a != b) {
p[a] = b;
res += w;
}
}
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;
}
}
例题:连接格点(grid)
又是多组读入…
import java.util.Scanner;
public class Main {
static int N = 1010;
static int M = N * N;
static int K = 2 * N * N;
static int n;
static int m;
static int k;
static int[][] ids = new int[N][N];
static int[] p= new int[M];
static Edge[] e = new Edge[K];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
for (int i = 1, t = 1; i <= n; i++) {
for (int j = 1; j <= m; j++, t++) {
ids[i][j] = t;
}
}
for (int i = 1; i <= n * m; i++) {
p[i] = i;
}
int x1, y1, x2, y2;
while (sc.hasNext()) {//读入方式..
x1 = sc.nextInt();
y1 = sc.nextInt();
x2 = sc.nextInt();
y2 = sc.nextInt();
int a = ids[x1][y1];
int b = ids[x2][y2];
p[find(a)] = find(b);
}
get_edges();
int res = 0;
for (int i = 0; i < k; i++) {
int a = find(e[i].a);
int b = find(e[i].b);
int w = e[i].w;
if (a != b) {
p[a] = b;
res += w;
}
}
System.out.println(res);
}
private static int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
private static void get_edges() {
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
int[] dw = {1, 2, 1, 2};
for (int z = 0; z < 2; z++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
for (int u = 0; u < 4; u++) {
if (u % 2 == z) {
int x = i + dx[u];
int y = j + dy[u];
int w = dw[u];
if (x != 0 && x <= n && y != 0 && y <= m) {
int a = ids[i][j];
int b = ids[x][y];
if (a < b) e[k++] = new Edge(a, b, w);
}
}
}
}
}
}
}
}
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;
}
}