1. 程式人生 > >《演算法導論》習題解答 Chapter 22.1-6(求universal sink 通用匯點)

《演算法導論》習題解答 Chapter 22.1-6(求universal sink 通用匯點)

思路:設定兩個遊標i指向行,j指向列,如果arr[i][j]==1,則i=max{i+1,j},j++;如果arr[i][j]==0,則j=max{i+1,j+1}。
虛擬碼:

has_universal_sink()
        for i=1 to N    //對角線檢查是否全是0
            if A[i][i]==1 return false;
	i=1,j=2
	while(i<=N && j<=N)
		if(A[i][j]==1)
                    i=max{i+1,j}
                    j++
		else
                    j=max{i+1,j+1}
        if i<=N
	    if check arr[i][*]=0,arr[*(except i)][i]=1 return true;
	    else return false;
        else
            return false;

命題:如果A[i][j]=0,則j不是通用匯點。
因為A[i][j]=0,說明i到j沒有邊,而通用匯點的定義是一定要每個點都要有一條指向他的邊,因此j不是通用匯點。

命題:如果A[i][j]=1,則i不是通用匯點。
因為A[i][j]=1,所以i到j有一條邊,所以i不是通用匯點。

迴圈不變式:每次迭代前,i之前和j之前但不包括i的點都不是通用匯點。
初始:i=1,j=2,i之前為空,j之前但不包括i的點也為空,因此成立。
保持:在迭代開始時,已知i之前和j之前但不包括i的點都不是通用匯點,當進入迴圈體後,如果A[i][j]==1,則說明i肯定不是通用匯點,並且已知j之前不包括i的點不是通用匯點,因此i=max{i+1,j},j++後仍然保持不變式;如果A[i][j]==0,則j不是通用匯點,如果j原本小於i,則j要到i+1,因為已知i之前的點肯定不是通用匯點,所以現在仍然保持不變式成立。
終止:如果i<=N,j=N+1,j之前除了i其他點都不是通用匯點,因此需要去全面檢查i是不是通用匯點。如果i=N+1,則不需要檢查了,沒有通用匯點。

命題:如果A[i][j]=1,則j之前的點都不是通用匯點。


命題:如果A[i][j]=0,則i之前的點都不是通用匯點。


輸入:

4 3
a c
b c
d c

原始碼:

package C22;

import java.io.ObjectInputStream.GetField;

/**
 * 此處提供兩種方法,一種是網上的方法,一種是自己想的方法,
 * 經過測試,如果同時執行100000000次,則網上的方法速度是3.6秒,我的方法速度是3秒
 * @author xiazdong
 *
 */
public class C1_6 {
	private static int sink_index = -1;
	public static void main(String[] args) throws Exception {
		Adjacent_Matrix adj_matrix = GraphFactory.getAdjacentMatrixInstance("input\\22.1-6.txt");
		boolean flag = has_universal_sink(adj_matrix);
		if(flag)System.out.println(adj_matrix.getVertexValue(sink_index));
	}
	/**
	 * 自己的方法
	 * @return
	 */
	public static boolean has_universal_sink(Adjacent_Matrix g){
		int i=0,j=0;
		boolean flag = true;
		while(j<=g.getSize()-1){
			if(g.getElement(i, j)==1){
				i = j;
			}
			j++;
		}
		//檢查arr[i][*]==0 arr[*(except i)][i]==1
		for(int a=0;a<g.getSize();a++){
			if(g.getElement(i, a)==1&&i!=a){
				flag = false;
			}
			if(g.getElement(a, i)==0&&i!=a){
				flag = false;
			}
		}
		if(flag) sink_index = i;
		return flag;
	}
	/**
	 * 網上的方法
	 * @return
	 */
	public static boolean has_universal_sink2(Adjacent_Matrix g){
		int i=0,j=0;
		boolean flag = true;
		while(j<=g.getSize()-1){
			if(g.getElement(i, j)==1){
				i++;
			}
			else
				j++;
		}
		//檢查arr[i][*]==0 arr[*(except i)][i]==1
		for(int a=0;a<g.getSize();a++){
			if(g.getElement(i, a)==1&&i!=a){
				flag = false;
			}
			if(g.getElement(a, i)==0&&i!=a){
				flag = false;
			}
		}
		if(flag) sink_index = i;
		return flag;
	}
}


這邊還有一篇跟通用匯點有關的博文,說實話,通用匯點的o(v)的求法我還不是搞的很懂,有空值得研究一下。

原文點此索引目錄。感謝xiazdong君 && Google醬。這裡是偶爾做做搬運工的水果君(^_^) )