Acwing 3728. 城市通电 java

原题链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

⭐ prim 最小生成树 O(n^2)

⭐ 记得开 long

import java.io.*;
import java.util.*;

public class Main
{
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));

	static int N = 2020, n;
	static int INF = 0x3f3f3f3f;


	static boolean[] st = new boolean[N];// 记录第 i 个点是否在连通块里边
	static long[] dist = new long[N];// dist 记录的是 i 到当前已知生成树的距离
	static long[] distp = new long[N];// 某点的父节点,即由哪个点扩展而来的,0 表示 是超级源点直连,即 建站
	static Node[] pos = new Node[N];// 城市坐标数组
	static int[] cp = new int[N];// city price 存在 i 城市建造一个发电站的费用
	static int[] k = new int[N];// 存每个城市的 常数 k

	static List<Integer> l1 = new ArrayList<>();// 记录建造发电站的城市
	static List<Node> l2 = new ArrayList<>();// 记录拉电线(边)的村庄

	static class Node
	{
		long x;
		long y;

		public Node(long x, long y)
		{
			super();
			this.x = x;
			this.y = y;
		}
	}

	static long prim()
	{
		long res = 0;
		Arrays.fill(dist,INF);
		st[0] = true;
		dist[0] = 0;
//		根节点是 超级源点 到任何一个城市的权重就是 该城市建站的费用
		for (int i = 1; i <= n; i++)
			dist[i] = cp[i];

		for (int i = 0; i < n; i++)//枚举 n 次把每个点都加入到最小生成树中
		{
		  //  找出距离当前点集合中距离最近的点
			int t = -1;
			for (int j = 1; j <= n; j++)//枚举每一个点,找出不在当前生成树的最短距离的点
				if (!st[j] && (t == -1 || dist[t] > dist[j]))
					t = j;

			st[t] = true;
			res += dist[t];
			
			if (distp[t] == 0)  //建站
				l1.add(t);
			else//普通村庄
			{
				l2.add(new Node(distp[t], t));
			}
//          用新加入的点更新其他点的距离
			for (int j = 1; j <= n; j++)
			{
				if (!st[j] && dist[j] > getEdge(t, j))
				{
					dist[j] = getEdge(t, j);// dist 记录的是 j 到当前生成树的距离
					distp[j] = t;//记录 j 的父节点 t
				}
			}

		}
		return res;
	}

//	求 a b 两个城市中边的长度
	static long getEdge(int a, int b)
	{
		long kk = k[a] + k[b];
		long dx = pos[a].x - pos[b].x;
		long dy = pos[a].y - pos[b].y;

		return kk * (Math.abs(dx) + Math.abs(dy));
	}

	public static void main(String[] args) throws IOException
	{
		n = Integer.parseInt(in.readLine());

//		输入城市位置
		for (int i = 1; i <= n; i++)
		{
			String[] split = in.readLine().split(" ");
			int x = Integer.parseInt(split[0]);
			int y = Integer.parseInt(split[1]);
			pos[i] = new Node(x, y);
		}

//		城市建站的费用
		String[] split = in.readLine().split(" ");
		for (int i = 1; i <= n; i++)
		{
			int x = Integer.parseInt(split[i - 1]);
			cp[i] = x;
		}

//		城市的电线单位价格
		String[] split2 = in.readLine().split(" ");
		for (int i = 1; i <= n; i++)
		{
			k[i] = Integer.parseInt(split2[i - 1]);
		}

		System.out.println(prim());
		System.out.println(l1.size());
		for (int x : l1)
		{
			System.out.print(x + " ");
		}
		System.out.println();
		System.out.println(l2.size());
		for (Node n : l2)
		{
			System.out.println(n.x + " " + n.y);
		}

	}

}

posted @ 2023-03-08 23:43  兑生  阅读(10)  评论(0编辑  收藏  举报  来源
Live2D