PAT 甲级1003 [java] 刷题

题目:

1003 Emergency (25 分)
As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:
Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N−1), M - the number of roads, C1 and C2- the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c​1, c​2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C​1 to C​2.

Output Specification:
For each test case, print in one line two numbers: the number of different shortest paths between C​1 and C​2, and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:
5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:
2 4

题目分析:有N个城市M条路,每个城市有不同的救援队,每条路有不同的权值。这样就转换成图论的问题。在一个已知权值的图中,求两点之间的最短路径,并保证点权最大,输出相应的边权和与点权和。(注意输出格式)

答题尝试:求最短路径,打算用求单源最短路径的Dijkstra算法 。

Dijkstra算法

建图
无论是哪种算法都需要建图,第一次用JAVA建图,参考了一下-另一个刷题的同学的做法
这里我写了两个类:一个顶点类,一个图类,用二维矩阵来保存图。代码如下:

/**
 * 建立顶点类 包含值与访问判断
 * @author hihiztc
 *
 */
class Vertex
{
	public int vertexValue;		//顶点的值
	public boolean isVisited;
	
	public Vertex(int value) {
		vertexValue=value;
		isVisited = false;	//给每个顶点设置访问标志,初值为false
	}
}


/**
 * 建立图类 
 * @author hihiztc
 *
 */
class Graph
{
	
	public Vertex vertexlis[];
	public int Martix[][];
	private int vertexCount;

	public Graph(int num)
	{
		vertexlis = new Vertex[num];
		Martix = new int [num][num];
		vertexCount = 0;
		
		//除到自身外,其余边全部初始化为无穷
		for(int j = 0;j<num;j++)
		{
			for(int k = 0;k<num;k++)
			{
				if(j==k) {
					Martix[j][j]=0;
				}
				else {
				Martix[j][k]=Integer.MAX_VALUE;
				}
			}
		}
	}
	
	//添加顶点
	public void addVertex(int value)
	{
		vertexlis[vertexCount++] = new Vertex(value);
	}
	
	//添加边
	public void addEdge(int start,int end,int value)
	{
		Martix[start][end]=value;
		Martix[end][start]=value;
	}
}

图建好后,接下来就对根据题目绘制出来的图进行最短路径的Dijkstra算法求解,Dijkstra算法对图进行逐步求解,每一次找到当前的最短路径,并不断用下次求解到的最短路径进行替换,最终得到源点到每个顶点的最短路径。
在代码中为实现题目的要求,增加了不同最短路径条数的数组num[]和点权和数组Vcount[]。
代码如下:

public class Main {
	private final static int MAX_VERTS = 505;
	private final static int INFINITY = Integer.MAX_VALUE;  
	private static int dist[] = new int [MAX_VERTS];	//最短路径长度
	private static int num[] = new int [MAX_VERTS];     //不同的最短路径条数
	private static int Vcount[] = new int [MAX_VERTS];	//顶点值和

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int N = in.nextInt();
		int M = in.nextInt();
		int C1 = in.nextInt();  	 //C1 为源点(Source)
		int C2 = in.nextInt();  	 //C2为终点(Destination)
		Graph citys = new Graph(N);	 //构造顶点数为N的图
		
		//添加顶点
		for(int i = 0 ;i<N;i++)
		{
			citys.addVertex(in.nextInt());
		}
		
		//添加边
		for(int i = 0;i<M;i++)
		{
			citys.addEdge(in.nextInt(),in.nextInt(), in.nextInt());
		}
		
		//填入到C1的最短距离,最短路径条数,点权和
		dist[C1]=0;
		num[C1]=1;
		Vcount[C1]=citys.vertexlis[C1].vertexValue;
		
		//初始化dist[]和Vcount[]
		for(int j=0;j<N;j++) {
			dist[j]=citys.Martix[C1][j];
			Vcount[j]=citys.vertexlis[j].vertexValue;
		}
		
		//对图中出了C1的顶点进行遍历
		for(int j=(C1+1)%N;j!=C1;j=(j+1)%N) {  
			int index =-1;
			int mindist = INFINITY;
			
			//从C1开始找寻与C1最短的边
			for(int k=0 ;k<N;k++) { 		
				if(!citys.vertexlis[k].isVisited && dist[k]<mindist) {
					mindist = dist[k];
					index = k;
				}
			}
			//没有最短路径,结束循环
			if(index == -1)   
				break;
				
			//将确定的节点设为true
			citys.vertexlis[index].isVisited = true; 
			
			//在index的基础上,寻找下一条最短路径
			for(int k=0;k<N;k++) {
				if(!citys.vertexlis[k].isVisited  && citys.Martix[index][k]!= INFINITY) {
					if(dist[k]>dist[index] +citys.Martix[index][k]) {
						dist[k]=dist[index] +citys.Martix[index][k];
						num[k] = num[index];			
						Vcount[k]=Vcount[index]+citys.vertexlis[k].vertexValue;
					}
					else if(dist[k] == dist[index] +citys.Martix[index][k]) {
						num[k]=num[index]+num[k];	
						if(Vcount[index]+citys.vertexlis[k].vertexValue>Vcount[k]) {
							Vcount[k]=Vcount[index]+citys.vertexlis[k].vertexValue;
						}
					}
				}
			}
		}
		//打印结果
		System.out.print(num[C2]+" "+Vcount[C2]);
	
	}

}

这样我们就做完了所有的事情,全部代码如下:

import java.util.Scanner;

/**
 * 建立顶点类 包含值与访问判断
 * @author hihiztc
 *
 */
class Vertex
{
	public int vertexValue;		//顶点的值
	public boolean isVisited;
	
	public Vertex(int value) {
		vertexValue=value;
		isVisited = false;	//给每个顶点设置访问标志,初值为false
	}
}


/**
 * 建立图类 
 * @author hihiztc
 *
 */
class Graph
{
	
	public Vertex vertexlis[];
	public int Martix[][];	
	private int vertexCount;


	public Graph(int num)
	{
		vertexlis = new Vertex[num];
		Martix = new int [num][num];
		vertexCount = 0;
		
		//除到自身外,其余边全部初始化为无穷
		for(int j = 0;j<num;j++)
		{
			for(int k = 0;k<num;k++)
			{
				if(j==k) {
					Martix[j][j]=0;
				}
				else {
				Martix[j][k]=Integer.MAX_VALUE;
				}
			}
		}
	}
	//添加顶点
	public void addVertex(int value)
	{
		vertexlis[vertexCount++] = new Vertex(value);
	}
	//添加边
	public void addEdge(int start,int end,int value)
	{
		Martix[start][end]=value;
		Martix[end][start]=value;
	}


	

	
}

public class Main {
	private final static int MAX_VERTS = 505;
	private final static int INFINITY = Integer.MAX_VALUE;  
	private static int dist[] = new int [MAX_VERTS];	//最短路径长度
	private static int num[] = new int [MAX_VERTS];     //不同的最短路径条数
	private static int Vcount[] = new int [MAX_VERTS];	//顶点值和

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int N = in.nextInt();
		int M = in.nextInt();
		int C1 = in.nextInt();  	 //C1 为源点(Source)
		int C2 = in.nextInt();  	 //C2为终点(Destination)
		Graph citys = new Graph(N);	 //构造顶点数为N的图
		
		//添加顶点
		for(int i = 0 ;i<N;i++)
		{
			citys.addVertex(in.nextInt());
		}
		
		//添加边
		for(int i = 0;i<M;i++)
		{
			citys.addEdge(in.nextInt(),in.nextInt(), in.nextInt());
		}
		
		dist[C1]=0;
		num[C1]=1;
		Vcount[C1]=citys.vertexlis[C1].vertexValue;
		
		//初始化dist[]和Vcount[]
		for(int j=0;j<N;j++) {
			dist[j]=citys.Martix[C1][j];
			Vcount[j]=citys.vertexlis[j].vertexValue;
		}
		
		for(int j=(C1+1)%N;j!=C1;j=(j+1)%N) {  
			int index =-1;
			int mindist = INFINITY;
			for(int k=0 ;k<N;k++) { 		//从C1开始找寻与C1最短的边
				if(!citys.vertexlis[k].isVisited && dist[k]<mindist) {
					mindist = dist[k];
					index = k;
				}
			}
			if(index == -1)   //没有最短路径,结束循环
				break;
			citys.vertexlis[index].isVisited = true; //将确定的节点设为true
			
			for(int k=0;k<N;k++) {
				if(!citys.vertexlis[k].isVisited  && citys.Martix[index][k]!= INFINITY) {
					if(dist[k]>dist[index] +citys.Martix[index][k]) {
						dist[k]=dist[index] +citys.Martix[index][k];
						num[k] = num[index];
						Vcount[k]=Vcount[index]+citys.vertexlis[k].vertexValue;
					}
					else if(dist[k] == dist[index] +citys.Martix[index][k]) {
						num[k]=num[index]+num[k];
						if(Vcount[index]+citys.vertexlis[k].vertexValue>Vcount[k]) {
							Vcount[k]=Vcount[index]+citys.vertexlis[k].vertexValue;
						}
					}
				}
			}
		}
		System.out.print(num[C2]+" "+Vcount[C2]);
	
	}

}

新手刷题,如果文章有错误,感谢指出,欢迎评论。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值