Codeforces Round #597 (Div. 2) D.Shichikuji and Power Grid(虚拟原点在最小生成树中的应用)

题意:
n个城市供电,要求每个城市或自己建立发电站,或与建立了发电站的城市直接或间接相连。给出每个点的横纵坐标xi,yi,以及每个点的建站花费和连线参数wi,ci,如果两座城市i、j之间连线,则花费为(ci+cj)*(ij之间的曼哈顿距离)。要求求出最小花费和建站的城市的编号以及连线的城市编号对。

我一开始的想法是,先找出建站花费最小的点,建站,然后对所有点跑一遍prim。之后,如果有的点的建站花费小于它在这个生成树上的边的花费,那么把这条边的花费减掉,加上建站花费。

官方给出的题解是,建一个超级点,也就是虚拟原点,使它到每个城市的花费为每个城市建站的花费,其余普通点之间的花费为连线花费,然后跑一遍prim即可。

感觉这两个想法道理应该是一样的,也可能我的贪心并不能达到全局最优。以下为使用官方思路的AC代码:

public class A {
	public static int maxn=2100;
	public static long ans=0,e[][]=new long[maxn][maxn],INF=Long.MAX_VALUE;
	public static long mincost[]=new long[maxn];
	public static int root[]=new int[maxn];
	public static boolean vis[]=new boolean[maxn];
	public static void prim(int n) {
		for(int i=0;i<=n;i++) {
			mincost[i]=INF;
		}
		mincost[0]=0;
		while(true) {
			int u=-1;
			for(int i=0;i<=n;i++) {
				if(!vis[i]&&(u==-1||mincost[i]<mincost[u])) {
					u=i;
				}
			}
			if(u==-1) {
				break;
			}
			vis[u]=true;
			ans+=mincost[u];
			for(int i=0;i<=n;i++) {
				if(!vis[i]&&mincost[i]>e[u][i]) {
					mincost[i]=e[u][i];
					root[i]=u;
				}
			}
		}
	}
	public static void main(String args[]) {
		InputReader sc=new InputReader(System.in);
		PrintWriter out=new PrintWriter(System.out);
		int n=sc.nextInt();
		int cd[][]=new int[maxn][4];
		for(int i=1;i<=n;i++) {
			cd[i][0]=sc.nextInt();
			cd[i][1]=sc.nextInt();
		}
		for(int i=1;i<=n;i++) {
			cd[i][2]=sc.nextInt();
		}
		for(int i=1;i<=n;i++) {
			cd[i][3]=sc.nextInt();
		}
		
		for(int i=1;i<=n;i++) {
			for(int j=i;j<=n;j++) {
				e[i][j]=e[j][i]=(long)(Math.abs((cd[i][0]-cd[j][0]))+Math.abs((cd[i][1]-cd[j][1])))*(cd[i][3]+cd[j][3]);
			}
			
		}
		for(int i=1;i<=n;i++) {
			e[i][0]=e[0][i]=cd[i][2];
		}
		prim(n);
		int jizhan[]=new int[maxn];
		int lianxian[][]=new int[maxn][2];
		int index1=0;
		int index2=0;
		for(int i=1;i<=n;i++) {
			if(root[i]==0) {
				jizhan[index1++]=i;
			}else {
				lianxian[index2][0]=i;
				lianxian[index2++][1]=root[i];
			}
		}
		out.println(ans);
		out.println(index1);
		for(int i=0;i<index1;i++) {
			out.print(jizhan[i]+" ");
		}
		out.println();
		out.println(index2);
		for(int i=0;i<index2;i++) {
			out.println(lianxian[i][0]+" "+lianxian[i][1]);
		}
		out.flush();
		out.close();
	}
}
发布了73 篇原创文章 · 获赞 3 · 访问量 3512

猜你喜欢

转载自blog.csdn.net/qq_42021845/article/details/102956092