poj 3767 I Wanna Go Home

来源:互联网 发布:美国eia数据在那里看 编辑:程序博客网 时间:2024/06/10 01:50
I Wanna Go Home
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 2541 Accepted: 1051

Description

The country is facing a terrible civil war----cities in the country are divided into two parts supporting different leaders. As a merchant, Mr. M does not pay attention to politics but he actually knows the severe situation, and your task is to help him reach home as soon as possible.

"For the sake of safety,", said Mr.M, "your route should contain at most 1 road which connects two cities of different camp."

Would you please tell Mr. M at least how long will it take to reach his sweet home?

Input

The input contains multiple test cases.

The first line of each case is an integer N (2<=N<=600), representing the number of cities in the country.

The second line contains one integer M (0<=M<=10000), which is the number of roads.

The following M lines are the information of the roads. Each line contains three integersA,B and T, which means the road between city A and cityB will cost timeT. T is in the range of [1,500].

Next part contains N integers, which are either 1 or 2. The i-th integer shows the supporting leader of cityi.

To simplify the problem, we assume that Mr. M starts from city 1 and his target is city 2. City 1 always supports leader 1 while city 2 is at the same side of leader 2.

Note that all roads are bidirectional and there is at most 1 road between two cities.

Input is ended with a case of N=0.

Output

For each test case, output one integer representing the minimum time to reach home.

If it is impossible to reach home according to Mr. M's demands, output -1 instead.

Sample Input

211 2 1001 2331 2 1001 3 402 3 501 2 1553 1 2005 3 1502 5 1604 3 1704 2 1701 2 2 2 10

Sample Output

10090540
 
解题报告:
o由于战争,一个商人想从城市1,回到自己的家城市2,其中城市1始终是由领导1,城市2始终由领导2,其中,商人回家的路中只能有一条路上连接由两个领导领导的城市,还有就是给出的路上双向的,也就是如果城市1能到城市2,那么城市2也同样能到城市1,这是关键。
o由于这个题中从1类城市走到2类城市后就不能再回去,只能穿过一次,所以先存为双向路,后面再根据不同类型的城市,把双向路变为单向路。
 
oN个城市,城市编号为1,2,3,……N
oM条路,路为双向路。 提供每条路的长度及端点城市编号,每两个城市之间直接连通的路最多一条。
o这N个城市分为两个集合,部分属于集合1,部分属于集合2,提供每个城市所属的集合,现要求从城市1出发去城市2,要求途径的路中最多出现一条其两端城市不属于同一个集合 的路,求出符合该条件下的从城市1到城市2的最短路,若不存在符合条件的路,输出-1
n注:数据中城市1必定属于集合1,城市2必定属于集合2  
 
o分析:由于城市1与城市2所属的集合固定,故在路径中必定有一条而且只能有一条路从属于集合 1的城市出发进入城市2,而定不会出现从集合2走向集合1的城市。
o如此,M条路中凡是连接属于不同集合的城市的路为单向路,只能从集合1中的城市走向集合2, 在此基础上用Dijkstra算法求最短路即可。
o核心算法 Dijkstra
 
import java.util.Arrays;import java.util.Scanner;/** *  @功能Function Description:    最短路径dijkstra *  @开发环境Environment:         eclipse * @技术特点Technique:           *  @算法:  思路一(下面的代码是这个思路的实现) *    1.先将按照所属领导,将区域分成两个集合,一个是属于领导1的集合,一个是属于领导2的集合 *    2.找到源点到两个集合的分界点的所有最短路径并保存(分界点:能从集合1到集合2只通过一个边的点,叫做分界点) *    3.找到重点到临界点的所有最短路径 *    4.找到两个集合临界点。如果任意两个点是联通的话就将他们的最短路径想加,再加上联通的边的值。 *    5.找到所有和的最小值,最小值即为所求。 *   *    思路二(我们老师讲的思路,比较简单,就是一个最基础的最短路径问题) *    主要:讲临界点的保存成单向的路径,然后用dijkstra算法求他的最短路径就是要求的值 *    具体思路:如上解题报告 *   *@版本Version:  Scanner *@作者Author:                  follow your dreams *@日期Date:                    20120809 *@备注Notes:                   求从源点到终点的最短路径。 *  @链接:                       http://poj.org/problem?id=3767 */public class PK3767_1_20120822 {public static int[][] map;public static int[] leader;public static int[] dist1;public static int[] dist2;public static void main(String[] args) {Scanner sc = new Scanner(System.in);int m, n;//n是城市的编号,m是道路int vertex1, vertex2, value;while(0 != (n=sc.nextInt())) {m = sc.nextInt();map = new int[n+1][n+1];leader = new int[n+1];//所在区域的领导for(int i=1; i<=m; i++) {vertex1 = sc.nextInt();vertex2 = sc.nextInt();value = sc.nextInt();map[vertex1][vertex2] = value;map[vertex2][vertex1] = value;}for(int i=1; i<=n; i++) {leader[i] = sc.nextInt();}dist1 = new int[n+1];dist2 = new int[n+1];Arrays.fill(dist1, Integer.MAX_VALUE);Arrays.fill(dist2, Integer.MAX_VALUE);dijkstra1();dijkstra2();//showArr(dist1);//showArr(dist2);System.out.println(calculator());}}/** * 计算顶点1到达领导1管辖范围的区域的边界 */public static void dijkstra1() {int len = map.length;boolean tag[] = new boolean[len];dist1[1] = 0;for(int i=1; i<len; i++) {//n次循环,有n个顶点,每次处理一个顶点int min = Integer.MAX_VALUE;int x = 0;for(int j=1; j<len; j++) {//在dist1[]中,寻找最小值if(!tag[j] && min>dist1[j]) {//当前顶点没有处理过,并且min不是最小值min = dist1[j];x = j;}}tag[x] = true;//标记x顶点处理过了if(leader[x] == 1) {//x属于领导1for(int j=1; j<len; j++) {//开始处理当前顶点xif(map[x][j]!=0 && leader[j]==1 && dist1[j]>dist1[x]+map[x][j]) {//当前边的存在(map[x][j]!=0),所到达的地区所属领导为1(leader[j]==1),当前距离比较大(dist1[j]>dist1[x]+map[x][j])dist1[j] = dist1[x]+map[x][j];}}}}}/** * 计算顶点2到达领导2管辖范围的区域的边界 */public static void dijkstra2() {int len = map.length;boolean tag[] = new boolean[len];dist2[2] = 0;for(int i=1; i<len; i++) {//n次循环,有n个顶点,每次处理一个顶点int min = Integer.MAX_VALUE;int x = 0;for(int j=1; j<len; j++) {//在dist1[]中,寻找最小值if(!tag[j] && min>dist2[j]) {//当前顶点没有处理过,并且min不是最小值min = dist2[j];x = j;}}tag[x] = true;//标记x顶点处理过了if(leader[x] == 2) {//x属于领导2for(int j=1; j<len; j++) {//开始处理当前顶点xif(map[x][j]!=0 && leader[j]==2 && dist2[j]>dist2[x]+map[x][j]) {//当前边的存在(map[x][j]!=0),所到达的地区所属领导为1(leader[j]==2),当前距离比较大(dist2[j]>dist2[x]+map[x][j])dist2[j] = dist2[x]+map[x][j];}}}}}/** *  * @return */public static int calculator() {int min = Integer.MAX_VALUE;int len = map.length;for(int i=1; i<len; i++) {if(dist1[i] != Integer.MAX_VALUE) {for(int j=1; j<len; j++) {if(dist2[j]!=Integer.MAX_VALUE && map[i][j]!=0) {if(min > dist2[j]+dist1[i]+map[i][j]) {min = dist2[j]+dist1[i]+map[i][j];}}}}}min = min==Integer.MAX_VALUE ? -1 : min;//如果min==最大值的话,说明没有找到路径return min;}public static void showArr(int[] arr) {for(int i=1; i<arr.length; i++) {System.out.print(arr[i] + "  ");}System.out.println();}}