1. 程式人生 > >萬惡的期末考試---演算法複習---遞迴與分治策略(二分搜尋與大數乘法與矩陣對角線相加,strassen矩陣乘法,棋盤覆蓋)

萬惡的期末考試---演算法複習---遞迴與分治策略(二分搜尋與大數乘法與矩陣對角線相加,strassen矩陣乘法,棋盤覆蓋)

已經考過三科了,還有三科,明天下午就要考演算法了,心慌慌,抓緊寫個部落格做演算法複習,靜靜心

呃呃呃  說好的只是複習下,自己拓展到了天外 ,第二章還沒結束....程式碼如下

大數乘法過程如下:

二分搜尋與大數乘法與矩陣對角線相加

package chap2_dgfz;

import java.util.Collections;

public class Z2 {

    public static void main(String[] args) {
//        int a[]={1,2,3,4};
//        int x=3;
//        int n=a.length;
//        System.out.println(binarySearch(a,x,n));
        
        int []a={8,2,1,6,5,4,7};
        int []b={9,6,7,8,5};
//        int []b={9,1};
        dscf(a,b);
        
    }
    
    /**
     *  二分搜尋技術
     * 將n個元素分成個數大致相同的兩半 a[n/2]==x a[n/2]<x  a[n/2]>x
     * 
     * 查詢的值是x,查詢的列表是a[],列表大小是n
     * 返回x在a[]中的下標
     * */
    public static int binarySearch(int []a,int x,int n){
        int left=0;int right=n-1;
        while(left<=right){
            int middle=(left+right)/2;
            if(x==a[middle]) return middle;
            if(x>a[middle]) left=middle+1;
            else right=middle-1;
        }
        return -1;
    }
    /**
     * 大數乘法
     * 印象中在大二上學過資料結構中用陣列進行大數計算,具體的忘了....
     * 課本沒有具體例子,在csdn借鑑https://blog.csdn.net/tjsinor2008/article/details/5625849
     * 以8216547*96785舉例  使用列表法 ①一位一位的列表 ②三位三位的列表
     * 
     * a[]是第一個大數       b[]是第二個大數
     * 
     * bl是行 al是列
     * **/
    public static void dscf(int []a,int []b){
        int al=a.length,bl=b.length;
        int res1[][] = new int[bl][al];
        for(int i=0;i<bl;i++){
            for(int j=0;j<al;j++){
                res1[i][j]=b[i]*a[j];
            }
        }
        
        for(int i=0;i<bl;i++){
            for(int j=0;j<al;j++){
                System.out.print(res1[i][j]+" ");
            }
            System.out.println();
        }
        djxxj(res1,al,bl);
        
        
        
        int[]num=new int[al+bl-1];
        int x=bl-1;
        int y=al-1;
        
        int jw=0;//進位
        int tsum=0;//暫時儲存的和
        
        for(int i=al+bl-2;i>=0;i--){
                if(x>=0){
                for(int m=x,n=al-1;n>=y&&m<=bl-1;m++,n--){
                    System.out.println(m+","+n);
                    tsum+=res1[m][n];
                }
                tsum+=jw;
                num[i]=tsum%10;
                jw=tsum/10;
                System.out.println("num:  "+tsum);
                tsum=0;
                x--;
                y--;
                System.out.println(i+"~~~!!!"+num[i]);
                System.out.println("jw:  "+jw);
                System.out.println("x,y:"+x+","+y);
                System.out.println();
                }else{
                    if(x==-1){y=al-2;}
                    
                    for(int m=0,n=y;n>=0&&m<=bl-1;m++,n--){
                        System.out.println(m+","+n);
                        tsum+=res1[m][n];
                    }
                    tsum+=jw;
                    if(y==0){
                        num[i]=tsum;
                    }else{
                    num[i]=tsum%10;}
                    jw=tsum/10;
                    System.out.println("num:  "+tsum);
                    tsum=0;
                    y--;
                    x=-2;
                    System.out.println(i+"~~~====="+num[i]);
                    System.out.println("jw:  "+jw);
                    System.out.println("x,y:"+x+","+y);
                    System.out.println();
                    
            }
        }
        
        for(int i=0;i<al+bl-1;i++){
            System.out.print(num[i]);
        }
    }
    /**
     * 對角線加法,列數大於等於行數
     * 由上面的函式推導而來
     * bl為行數 al為列數
     * **/
    public static void djxxj(int [][]res1,int al,int bl){
        
        int[]num=new int[al+bl-1];
        int tsum=0;//暫時儲存的和
        int x=bl-1;
        int y=al-1;
        for(int i=al+bl-2;i>=0;i--){
            if(x>=0){
            for(int m=x,n=al-1;n>=y&&m<=bl-1;m++,n--){
                System.out.println(m+","+n);
                tsum+=res1[m][n];
                System.out.println(tsum);
            }
            num[i]=tsum;
            tsum=0;
            x--;
            y--;
            }else{
                if(x==-1){y=al-2;}
                
                for(int m=0,n=y;n>=0&&m<=bl-1;m++,n--){
                    System.out.println(m+","+n);
                    tsum+=res1[m][n];
                }
                if(y==0){
                    num[i]=tsum;
                }else{
                num[i]=tsum;}
                System.out.println("num:  "+tsum);
                tsum=0;
                y--;
                x=-2;
                
        }
    }
        
        System.out.println("對角線求和結果");
        for(int i=0;i<al+bl-1;i++){
            System.out.print(num[i]+" ");
        }
        System.out.println();
    }
}


stressen矩陣乘法

把每個矩陣分割為4份,然後建立如下10箇中間矩陣:

S1 = B12 - B22
S2 = A11 + A12
S3 = A21 + A22
S4 = B21 - B11
S5 = A11 + A22
S6 = B11 + B22
S7 = A12 - A22
S8 = B21 + B22
S9 = A11 - A21
S10 = B11 + B12

接著,計算7次矩陣乘法:

P1 = A11 • S1
P2 = S2 • B22
P3 = S3 • B11
P4 = A22 • S4
P5 = S5 • S6
P6 = S7 • S8
P7 = S9 • S10

最後,根據這7個結果就可以計算出C矩陣:
C11 = P5 + P4 - P2 + P6
C12 = P1 + P2
C21 = P3 + P4
C22 = P5 + P1 - P3 - P7

棋盤覆蓋

 

package chap2_dgfz;

public class ChessBoard {
        int tile=1;//表示L型骨牌的編號
        int[][] board = new int[4][4];//表示棋盤
        /**
         * 處理帶有特殊棋子的棋盤.tr、tc表示棋盤的入口即左上角的行列號,dr、dc表示特殊棋子的行列位置,size表示棋盤的行數或者列數
         * */
        public void chessBoard(int tr, int tc, int dr, int dc, int size)
        {
            if(size == 1) return;
            int t = tile++;
            System.out.println(t);
            int s = size/2;//每一次化大棋盤為一半的子棋盤
            //要處理帶有特殊棋子的棋盤,第一步先處理左上棋盤
            if(dr < tr + s && dc< tc + s)//左上角子棋盤有特殊棋子
                chessBoard(tr,tc,dr,dc,s);//處理有特殊棋子的左上角子棋盤
            else//處理無特殊棋子的左上角子棋盤
            {
                board[tr+s-1][tc+s-1] = t;
                //設左上角子棋盤的右下角為特殊棋子,用t型的骨牌覆蓋。由於骨牌有三種,當處理過程中同一級設定的特殊棋子用相同的骨牌覆蓋
                chessBoard(tr,tc,tr+s-1,tc+s-1, s);//處理有用骨牌覆蓋的格子作為特殊棋子的左上角子棋盤
            }
            
            //第二步處理右上角棋盤
            if(dr < tr+s && dc >=tc+s)//右上角子棋盤有特殊棋子
            {
                chessBoard(tr,tc+s,dr,dc,s);//處理有特殊棋子的右上角子棋盤
            }    
            else
            {
                board[tr+s-1][tc+s] =t;//設右上角子棋盤的左下角為特殊棋子,用t型的骨牌覆蓋。由於骨牌有三種,當處理過程中同一級設定的特殊棋子用相同的骨牌覆蓋
                chessBoard(tr,tc+s,tr+s-1,tc+s,s);//處理有用骨牌覆蓋的格子作為特殊棋子的右上角子棋盤
            }
            
            //第三步處理左下角子棋盤
            if(dr >=tr+s && dc<tc+s)//左下角子棋盤有特殊棋子
            {
                chessBoard(tr+s,tc,dr,dc,s);//處理有特殊棋子的左下角子棋盤
            }
            else
            {
                board[tr+s][tc+s-1] = t;//設左下角子棋盤的右上角為特殊棋子,用t型的骨牌覆蓋。由於骨牌有三種,當處理過程中同一級設定的特殊棋子用相同的骨牌覆蓋
                chessBoard(tr+s,tc,tr+s,tc+s-1,s);//處理有用骨牌覆蓋的格子作為特殊棋子的左下角子棋盤
            }
            
            //第四步處理右下角棋盤
            if(dr>=tr+s&& dc>= tc+s)//右下角子棋盤有特殊棋子
            {  
                chessBoard(tr+s,tc+s,dr,dc,s);//處理有特殊棋子的右下角子棋盤
            }
            else
            {
                board[tr+s][tc+s] = t;//設子棋盤右下角的左上角為特殊棋子,用t型的骨牌覆蓋。由於骨牌有三種,當處理過程中同一級設定的特殊棋子用相同的骨牌覆蓋
                chessBoard(tr+s,tc+s,tr+s,tc+s,s);//處理有用 骨牌覆蓋的格子作為特殊棋子的右下角子棋盤
            }
        }
        
        public static void main(String[] args)
        {
            ChessBoard c = new ChessBoard();
            c.chessBoard(0,0,2,1,4);
            for(int i = 0; i <4; i++)
            {    for(int j = 0; j <4; j++)
                    System.out.print(c.board[i][j]+"  ");
            System.out.println();
            }
        }
    }