萬惡的期末考試---演算法複習---遞迴與分治策略(二分搜尋與大數乘法與矩陣對角線相加,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();
}
}
}