道路和航路 Java實現

問題描述

農夫約翰正在針對一個新區域的牛奶配送合同進行研究。他打算分發牛奶到T個城鎮(標號爲1..T),這些城鎮通過R條標號爲(1..R)的道路和P條標號爲(1..P)的航路相連。

每一條公路i或者航路i表示成連接城鎮Ai(1<=A_i<=T)和Bi(1<=Bi<=T)代價爲Ci。每一條公路,Ci的範圍爲0<=Ci<=10,000;由於奇怪的運營策略,每一條航路的Ci可能爲負的,也就是-10,000<=Ci<=10,000。

每一條公路都是雙向的,正向和反向的花費是一樣的,都是非負的。

每一條航路都根據輸入的Ai和Bi進行從Ai->Bi的單向通行。實際上,如果現在有一條航路是從Ai到Bi的話,那麼意味着肯定沒有通行方案從Bi回到Ai。

農夫約翰想把他那優良的牛奶從配送中心送到各個城鎮,當然希望代價越小越好,你可以幫助他嘛?配送中心位於城鎮S中(1<=S<=T)。

輸入格式

輸入的第一行包含四個用空格隔開的整數T,R,P,S。

接下來R行,描述公路信息,每行包含三個整數,分別表示Ai,Bi和Ci。

接下來P行,描述航路信息,每行包含三個整數,分別表示Ai,Bi和Ci。

輸出格式

輸出T行,分別表示從城鎮S到每個城市的最小花費,如果到不了的話輸出NO PATH。 

樣例輸入

6 3 3 4
1 2 5
3 4 5
5 6 10
3 5 -100
4 6 -100
1 3 -10 

樣例輸出

NO PATH
NO PATH
5
0
-95
-100 

數據規模與約定

對於20%的數據,T<=100,R<=500,P<=500;

對於30%的數據,R<=1000,R<=10000,P<=3000;

對於100%的數據,1<=T<=25000,1<=R<=50000,1<=P<=50000。

解答:主要運用深度優先搜索和權值約束。相關知識參見http://blog.163.com/zhoumhan_0351/blog/static/3995422720098342257387/

下面有兩個程序可供參考

實現的Java算法如下

(由於採用遞歸,在測試大規模數據時會報java.lang.StackOverflowError錯誤。)

import java.util.Scanner;
import java.util.Stack;
public class MinCost {
    static Stack<Integer> stack = new Stack<Integer>();//堆棧
    static Stack<Integer> cost = new Stack<Integer>();//花費的堆棧
    static int temp =0;
    public static void main(String []args)
    {
        Scanner ss = new Scanner(System.in);
        int T = ss.nextInt();
        int min[] = new int[T+1];
        int parents[] = new int[T+1];
        int R =  ss.nextInt();
        int P = ss.nextInt();
        int S = ss.nextInt();
        int A[] = new int[2*R+P+1];
        int B[] = new int[2*R+P+1];
        int C[] = new int[2*R+P+1];
        int a,b,c;
        for(int i=1;i<=T;i++)//訪問標誌初始化
        {
            parents[i] =  0;
        }
        for(int i=1;i<=2*R;i++)
        {
            a = ss.nextInt();
            b = ss.nextInt();
            c = ss.nextInt();
            A[i] = a;B[i] = b;C[i] = c;
            i++;
            A[i] = b;B[i] = a;C[i] = c;
        }
        for(int i=2*R+1;i<=2*R+P;i++)
        {
            A[i] = ss.nextInt();
            B[i] = ss.nextInt();
            C[i] = ss.nextInt();
        }
        stack.push(S);//將出發城鎮初始化
        min[S] = 0;
        cost.push(0);
        int mini[] = DFS(A,B,C,min,parents);
        for(int i=1;i<mini.length;i++)
        {
            if(i!=S&&mini[i]==0)
                System.out.println("NOPATH");
            else
                System.out.println(mini[i]);
        }
    }
    public static int[] DFS(int[] A,int[] B ,int[] C,int[] min,int[] parents)
    {
        for(int i=1;i<A.length;i++)
        {
            if(A[i]==stack.peek()&&checkParents(B[i],parents)&&check(B[i]))
            {
                stack.push(B[i]);
                cost.push(cost.peek()+C[i]);
                parents[stack.peek()] = A[i];
                if(min[B[i]]==0||min[B[i]]>cost.peek())
                {
                    min[B[i]] = cost.peek();
                }
                DFS(A,B,C,min,parents);
            }
        }

        if(stack.peek()==stack.get(0))
            return min;
        cost.pop();
        stack.pop();
        DFS(A,B,C,min,parents);
        return min;
    }
    public static boolean check(int n)
    {
        boolean flag = true;
        for(int i=0;i<stack.size();i++)
        {
            if(n==stack.get(i))
            {
                flag = false;
                break;
            }
        }
        return flag;
    }
    public static boolean checkParents(int n,int[] parents)
    {
        if(parents[n]==stack.peek())
            return false;
        else
            return true;
    }
}


非遞歸程序(木有大量測試數據)

import java.util.Scanner;
import java.util.Stack;
public class TT {
	public static int S;
	public static void main(String []args)
	{

		int minx[] = DFS();
		for(int i=1;i<minx.length;i++)
		{
			if(i!=S&&minx[i]==0)
				System.out.println("NO PATH");
			else
				System.out.println(minx[i]);
		}
	}
	public static int[] DFS()
	{
		Scanner ss = new Scanner(System.in);
		int T = ss.nextInt();//輸入城市數
		int R =  ss.nextInt();//輸入道路數
		int P = ss.nextInt();//輸入航路數
		S = ss.nextInt();//輸入出發城鎮
		int min[] = new int[T+1];//記錄到每個城鎮的最小花費
		int C[][] = new int[T+1][T+1];//C[i][j]表示記錄從i城鎮到j城鎮的花費
		boolean visit[] = new boolean[T+1];//標記每個城市是否被訪問過
		Stack<Integer> stack = new Stack<Integer>();//堆棧
		Stack<Integer> cost = new Stack<Integer>();//花費的堆棧
		int temp =0;
		Stack<Integer>[] city = new Stack[T+1];//記錄每個每個城鎮爲出發點的所有道路或航路
		int flag[] = new int[T+1];//記錄該城鎮爲訪問節點爲i時的下一個訪問節點在city[]中的位置
		for(int i=1;i<city.length;i++)//將city[]數組初始化
		{
			city[i] = new Stack<Integer>();
		}
		for(int i=1;i<visit.length;i++)//將visit[]數組初始化
			for(int j=1;j<visit.length;j++)
			{
				visit[i] = false;
			}
		int m,n,k;
		for(int i=1;i<=R;i++)//將city[]數組賦值
		{
			m = ss.nextInt();
			n = ss.nextInt();
			k = ss.nextInt();
			city[m].add(n);C[m][n]=k;
			city[n].add(m);C[n][m]=k;
		}
		for(int i=1;i<=P;i++)//將city[]數組賦值
		{
			m = ss.nextInt();
			n = ss.nextInt();
			k = ss.nextInt();
			city[m].add(n);C[m][n]=k;
		}
		stack.push(S);//將出發城鎮壓入堆棧
		min[S] = 0;//將出發城鎮的最小花費置0
		cost.push(0);//花費初始壓入0
		visit[S] = true;//將出發城鎮訪問位置true
		/*
		 * 由深度優先搜索對所有路徑進行遍歷
		 */
		int i;
		while(true)
		{
			while(true)
			{
				int a = stack.peek();//取出訪問節點
				for(i=flag[a];i<city[a].size();i++)//在city[]遍歷訪問
				{
					int b =city[a].get(i);
					if(!visit[b])//判斷下一個節點是否被訪問過
					{
						/*
						 * 如果下個節點可被訪問。則將相應數據壓入堆棧.並把被城鎮的city[]數組的訪問位flag[]+1
						 */
						cost.push(cost.peek()+C[a][b]);//將到下一個節點所需花費壓入cost堆棧
						flag[a]++;
						visit[b] = true;
						stack.push(b);
						int c = stack.peek();
						System.out.println(c+" "+min[c]+" "+cost.peek());
						if(min[c]==0||min[c]>cost.peek())//判斷是否到該訪問節點是否是已有路徑到該節點的最小花費
						{
							min[c] = cost.peek();
						}
						break;//退出 ,進去下一個節點的訪問
					}
				}
				if(i==city[a].size())
				  break;//如果遍歷該節點的city[]數組,都沒有可訪問的下一個節點則退出,進行回退操作
			}
			/*
			 * 如果沒有找到下一個節點。則回退,相應數據出棧
			 */
			int d = stack.peek();
			if(d==stack.get(0))//如果將要出棧數據爲出發城鎮則遍歷結束。退出。
				break;
			visit[d]=false;
			cost.pop();
			stack.pop();
		}
		
		return min;
	}
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章