题目:
一家六口,一个爸爸,一个妈妈,俩儿子,俩女儿,还有一个警察,一个坏蛋,过一条河。
爸爸不在妈妈伤害儿子,妈妈不在爸爸伤害女儿,警察不在坏蛋伤害一家六口。
只有妈妈爸爸警察会开船,一次只能过两个人,只有一艘船。
用程序实现怎么过河。
思路见程序:
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!!!