精華帖——八人過河的程式實現
阿新 • • 發佈:2019-01-31
題目:
一家六口,一個爸爸,一個媽媽,倆兒子,倆女兒,還有一個警察,一個壞蛋,過一條河。
爸爸不在媽媽傷害兒子,媽媽不在爸爸傷害女兒,警察不在壞蛋傷害一家六口。
只有媽媽爸爸警察會開船,一次只能過兩個人,只有一艘船。
用程式實現怎麼過河。
思路見程式:
題外話:這是面試某狗測試崗的課外作業。哈哈~~include<iostream> #include <vector> #include <stdio.h> using namespace std; /*總體思路:用一個9位的整數表示,當前所處的狀態,最高位表示河的左岸或者右岸。低8位依次表示警察,犯人,父親 母親,2個兒子,2個女兒;一次渡河可以看成是2個狀態之間的轉移。 總體分兩步進行; Step 1:先算出轉移矩陣 Step 2:利用迪傑斯特拉算出,源點到終點最短路徑,所經歷的結點。 */ #define MAX 10000//結點間的最大值,表示兩個狀態不能轉換 #define N 512//表示狀態向量,以9bit值表示。eg:0 1111 1111表示開始狀態,所有的8個人在河的左岸。 const int lrmask=1<<8;//0表示在河的左岸,1表示在河的右岸。 const int cap= 1<<7;//表示警察的狀態 const int criminal=1<<6;//表示犯人的狀態 const int father=1<<5;//表示爸爸的狀態 const int mother=1<<4;//表示媽媽的狀態 const int son=3<<2;//表示兩個兒子的狀態 const int daughter=3;//表示兩個女兒的狀態 bool is_possible_state(int x)//判斷某個狀態是否滿足規則 { if ((x&criminal)&&(!(x&cap))&&(x&(father+mother+son+daughter)))//表示警察不在的時候,犯人不能與6口家人在一起 return false; if ((x&father)&&(!(x&mother))&&(x&daughter))//表示媽媽不在,爸爸不能與女兒在一起 return false; if ((x&mother)&&(!(x&father))&&(x&son))//表示爸爸不在,媽媽不能與兒子在一起 return false; else return true;//其它為有效狀態 } bool is_possible_vec(unsigned char x)//判斷在船上的狀態 { int num=0; int tmp=x; if (x==0)//表示狀態向量的值為0 ,沒人乘船,無效狀態 return false; while(tmp) { num++; if (num>2)//當多餘2個人乘船,無效狀態 return false; tmp=tmp&(tmp-1);//判斷幾個人乘船 } if ((x&criminal)&&(!(x&cap))&&(x&(father+mother+son+daughter)))//判斷該狀態是否滿足規則 return false; if ((x&father)&&(!(x&mother))&&(x&daughter)) return false; if ((x&mother)&&(!(x&father))&&(x&son)) return false; else return true;//滿足情況,返回true. } void Dijkstra(int v, int **dist,int D[N],int p[N],int s[N]) { int i, j, k, v1, min, max=10000, pre; v1=v; for( i=0; i<N; i++) { D[i]=dist[v1][i]; if( D[i] != MAX ) p[i]= v1+1; else p[i]=0; s[i]=0; } s[v1]=1; for( i=0; i<N-1; i++) { min=10001; for( j=0; j<N-1; j++) if ( ( !s[j] )&&(D[j]<min) ) {min=D[j]; k=j; } s[k]=1; for(j=0; j<N; j++) if ( (!s[j])&&(D[j]>D[k]+dist[k][j]) ) {D[j]=D[k]+dist[k][j]; p[j]=k+1; } } for(i=511; i<512; i++) //僅輸出從源點狀態0 1111 1111 到終點狀態 1 0000 0000的路徑 { printf(" %d : %d ", D[i], i); pre=p[i]; while ((pre!=0)&&(pre!=v+1)) { printf ("<- %d ", pre-1); pre=p[pre-1]; } printf("<-%d \n", v); } } int main() { int **matrix=(int **)malloc(N*sizeof(int *));//建立二維狀態矩陣matrix[N][N] for (int i=0;i<N;i++) { matrix[i]=(int *)malloc(N*sizeof(int)); } //計算矩陣的值,即計算結點之間的路徑。1表示可以連線,0表示自己與自己路徑,MAX表示結點間不相連線 for(int i=0;i<N;i++) { for (int j=0;j<N;j++) { if (i==j) matrix[i][j]=0;//自己與自己的距離為0 else if(((i&lrmask)^(j&lrmask))&&is_possible_state(~j)&&is_possible_state(i)&&is_possible_state(~j)&&is_possible_state(j)) { //當滿足i,j分別為某次轉移前左岸的狀態與轉移後右岸的狀態; //~i和~j分別表示某次轉移前右岸的狀態與轉移後左岸的狀態 unsigned char i0=i%256;//i0,j0分別表示狀態向量值的後八位,即八個人在左岸與右岸的狀態 unsigned char j0=j%256; unsigned char tmp=~i0^j0;//tmp表示轉移向量值,即某次那些人狀態發生了改變 //在滿足上述情況的基礎上,tmp轉移向量值有效 if(((unsigned char)i0>(unsigned char)(~j0))&&is_possible_vec(tmp)&&!(tmp-(tmp&i0))) matrix[i][j]=1; else matrix[i][j]=MAX;//表示節點間不相連 } else matrix[i][j]=MAX;//表示節點間不相連 } } int D[N]={0};//陣列D表示經過了幾個結點 int p[N]={0};//陣列P儲存的是從源點到終點經過了那些結點 int s[N]={0};//儲存已經找到的結點 int num=0; Dijkstra(255,matrix,D,p,s);//運用迪傑斯特拉演算法,初始狀態從0 1111 1111開始 }
霸面某狗,遇到一個很nice的面試官,問的問題雖然回答的不是特別好,但是卻讓我大開眼界,原來類似智力題這麼好玩!!!哈哈~~
下午3點結束面試,拿到的題目——之前聽過沒做過的題目。來不及馬上做,又去趕另一家網際網路的面試。唉,一波面試向我襲來,有些措手不及。
晚上回去搜一下,原來是個小遊戲。哈哈,從沒想過自己能寫出個遊戲。
整個思考過程表示很痛苦,痛並快樂著。整個晚上很high,熬到夜裡3點多。。。竟然不感覺困。。。
因為剛開始思路有點繞路了,耽誤些時間,提交時間晚了2個多小時。所以,這可能也是沒通過的原因之一。
不過,找到了許久以來沒有的學習興趣與熱情。。。。哈哈,很nice!!!