3传教士与3野人过河问题的A*算法

clc;

clear;

global State;

 

%此程序计算传教士与野人问题:

%三个传教士与三个野人分别站在河的两岸,有一条船,可以载一至两人。要求用船载人,把三个传教士、野人载过岸,要求每个地方的野人数量不能大于传教士

% 初始状态:

%    'Fa1'  '   '  'Sa1'

%    'Fa2'  '   '  'Sa2'

%    'Fa3'          'Sa3'

% 

% 最终状态

%    'Sa1'  '   '  'Fa1'

%    'Sa2'  '   '  'Fa2'

%    'Sa3'          'Fa3'

 

%定义初始状态

%河的左岸为3个传教士,0个野人

%河的右岸为0个传教士,3个野人

State_Begin =  { 'Fa' , 'Fa', 'Fa' 'Sa', 'Sa', 'Sa' 'none','none'};

 

%最终状态

%河的左岸为0个传教士,3个野人

%河的右岸为3个传教士,0个野人

%State_Final =  { 'Sa', 'Sa', 'Sa'  'Fa' , 'Fa', 'Fa' 'none', 'none'};

 

%生成State的序列,结果就是State_Begin -> State1 -> State2 -> State3 -> .....->State_Final

    %构建状态点,包含当前节点编号(No_now), 父节点编号(No_dad),f,g,是否已被展开过(1为展开过,0为未展开),当前状态(8个状态变量)

    %初始状态

   State ={'No_now','No_dad','f','g','Flag','State_L1','State_L2','State_L3','State_R1','State_R2','State_R3','State_B1','State_B2'};

    

   g=1;

    h= fun_h(State_Begin);

    f= h + g;

   Flag = 0;  %未被展开

   State =[State ;[1,1,f,g,Flag,State_Begin]];

    

   while h~=0

       %展开结点,并将展开的节点状态从后面加入State

       ind = find(cell2mat(State(2:end,5))==0); %找到没有被展开的接点

       %由没展开的接点组成新的State

       State_new = State(ind+1 , :);

       

       fmin = min(cell2mat(State_new(:,3)));

       

       ind_new = find(cell2mat(State_new(:,3)) == fmin);

                

       if length(ind_new)==1

           No_now_tmp = ind_new;

           else

           No_now_tmp = ind_new(1);

       end

       

       No_now = State_new{No_now_tmp,1};

 

       fun_unfold(No_now);

       %判断是否获得了终点状态

       mat_h = cell2mat(State(2:end,3)) - cell2mat(State(2:end,4));

       indh = find(mat_h == 0);

        if isempty(indh)==1

           h = 1;

       else

           h = 0;

       end

       

    end

   

 

% %显示结果

% 数据格式为{'No_now','No_dad','f','g','Flag','State_L1','State_L2','State_L3','State_R1','State_R2','State_R3','State_B1','State_B2'}

 

mat_h = cell2mat(State(2:end,3)) -cell2mat(State(2:end,4));

ind = find( mat_h == 0 );  

       if length(ind)==1

           No_now_tmp = ind;

       else

           No_now_tmp = ind(1);

       end

No_now = State{No_now_tmp+1,1};

disp(State(No_now_tmp+1,6:end));

while No_now ~= 1

   No_now = State{No_now+1,2};

   ind =  find(cell2mat(State(2:end,1)) == No_now );

   disp('                       /\  /\    ');

   disp('                       |   |    ');

   disp(State(ind+1,6:end));

end

 

function fun_unfold(No_now)

    

   global State;

    %数据格式为{'No_now','No_dad','f','g','Flag','State_L1','State_L2','State_L3','State_R1','State_R2','State_R3','State_B1','State_B2'}

   State_unfold = State(No_now+1,:);

    

    %每展开一次,层数就相对上层增加1层

    g= State_unfold{4} + 1;

    

   for i=6:11

       for j=6:11

           State_tmp = State_unfold;

          

           tmp = State_tmp{i};

           State_tmp{i} = State_tmp{12};

           State_tmp{12} = tmp;

 

           tmp = State_tmp{j};

           State_tmp{j} = State_tmp{13};

           State_tmp{13} = tmp;

 

           check = fun_check(State_tmp(6:13));

           if check == 1

                f =  fun_h(State_tmp(6:13)) + g;

                State_tmp{3} = f; 

                State_tmp{4} = g;

                State_tmp{2} = No_now ;   % 父节点即为No_now 结点

                [r,~] = size(State);

                State_tmp{1} = r;

                State = [State ; State_tmp];

           end

           

       end

   end

   State{No_now+1,5} = 1;

end

 

function [check]=fun_check(State_now)

    %分别统计两岸的野人数和神父数,要求野人数不要大于神父数,否则返回0

    %左岸检查

   Fa1=0;

   Sa1=0;

   check1 = 0;

   check2 = 0;

   for i=1:3

       if strcmp(State_now{i},'Fa')==1

 

           Fa1 = Fa1+1;

       elseif strcmp(State_now{i},'Sa')==1

           Sa1 = Sa1+1;

       end

   end

    

   if (Fa1 ~= 0) && (Sa1 >Fa1)

       check = 0;

   else

       check1 = 1;

   end

 

    %右岸检查

   Fa2=0;

   Sa2=0;

   for i=4:6

       if strcmp(State_now{i},'Fa')==1

           Fa2 = Fa2+1;

       elseif strcmp(State_now{i},'Sa')==1

           Sa2 = Sa2+1;

       end

   end

    

   if (Fa2 ~= 0) && (Sa2 >Fa2)

       check = 0;

   else

       check2 = 1;

   end

       

   if check2 == 1 && check1 ==1

       check =1;

 

   else

       check =0;

 

   end

 

end

 

function h = fun_h (state)

 %%h为从当前状态到目标状态的代价

 

 %最终状态

%河的左岸为0个传教士,3个野人

%河的右岸为3个传教士,0个野人

%State_Final =  { 'Sa', 'Sa', 'Sa'  'Fa' , 'Fa', 'Fa' 'none', 'none'};

h = 0;

for i=1:3

   if strcmp(state{i},'Sa')~=1

       h = h + 1;

   end

end

 

for i=4:6

   if strcmp(state{i},'Fa')~=1

       h = h + 1;

   end

end

end 

版权保留,不对以上代码负责

交流请联系huiweis的gmail邮箱

 

转载于:https://www.cnblogs.com/shekarry/p/5348248.html

传教士野人过河问题是一个经典的人工智能搜索问题。A*算法是一种启发式搜索算法,可以用来解决这个问题。 首先,我们需要定义问题的状态和操作。在本问题中,状态由河岸上的传教士野人的数量以及船的位置确定。操作包括:1. 一个人或两个人乘船过河;2. 将船回到原来的河岸。 接下来,我们可以使用A*算法来搜索最优解。A*算法在搜索过程中使用一个估价函数来估计从当前状态到目标状态的距离。在本问题中,我们可以使用下面这个估价函数: h(n) = (m_left + c_left - 2) / 2 + (m_right + c_right - 2) / 2 + boat 其中m_left和c_left表示左岸上的传教士野人数量,m_right和c_right表示右岸上的传教士野人数量,boat表示船的位置(0表示在左岸,1表示在右岸)。这个估价函数的含义是,我们希望尽快将所有的传教士野人都从左岸移到右岸,因此我们估计的距离就是左岸和右岸上的传教士野人数量之和减去2,再除以2(因为每次乘船最多只能带2个人)。 然后,我们可以使用A*算法来搜索最优解。具体来说,我们需要定义一个状态类,其中包含当前状态的信息,以及f、g和h三个变量。其中,f表示当前状态的估价函数值,g表示从起始状态到当前状态的距离(即已经乘船的次数),h表示当前状态到目标状态的估计距离。然后,我们需要定义一个优先队列,按照f值从小到大排序,每次取出f值最小的状态进行扩展,并将扩展出的新状态加入队列中。直到找到目标状态或者队列为空为止。 下面是一个简单的Java实现,仅供参考: ```java import java.util.*; public class MissionaryAndCannibal { static class State { int ml, cl, mr, cr, boat, g, h, f; State(int ml, int cl, int mr, int cr, int boat, int g, int h) { this.ml = ml; this.cl = cl; this.mr = mr; this.cr = cr; this.boat = boat; this.g = g; this.h = h; this.f = g + h; } } static int h(int ml, int cl, int mr, int cr, int boat) { return (ml + cl - 2) / 2 + (mr + cr - 2) / 2 + boat; } static boolean isValid(int m, int c) { return m >= 0 && c >= 0 && (m == 0 || m >= c); } static List<State> getSuccessors(State s) { List<State> successors = new ArrayList<>(); int[] deltaM = {1, 2, 0, 0, 1}; int[] deltaC = {0, 0, 1, 2, 1}; for (int i = 0; i < 5; i++) { int newMl = s.ml - deltaM[i] * s.boat; int newCl = s.cl - deltaC[i] * s.boat; int newMr = s.mr + deltaM[i] * s.boat; int newCr = s.cr + deltaC[i] * s.boat; int newBoat = 1 - s.boat; int newG = s.g + 1; int newH = h(newMl, newCl, newMr, newCr, newBoat); if (isValid(newMl, newCl) && isValid(newMr, newCr)) { State newState = new State(newMl, newCl, newMr, newCr, newBoat, newG, newH); successors.add(newState); } } return successors; } static boolean isGoal(State s) { return s.ml == 0 && s.cl == 0; } static List<State> aStarSearch(State start) { PriorityQueue<State> open = new PriorityQueue<>(Comparator.comparingInt(s -> s.f)); Set<State> closed = new HashSet<>(); open.add(start); while (!open.isEmpty()) { State current = open.poll(); if (isGoal(current)) { List<State> path = new ArrayList<>(); while (current != null) { path.add(current); current = current.parent; } Collections.reverse(path); return path; } closed.add(current); for (State successor : getSuccessors(current)) { if (closed.contains(successor)) continue; if (!open.contains(successor)) { successor.parent = current; open.add(successor); } else { State existing = open.stream().filter(s -> s.equals(successor)).findFirst().get(); if (successor.g < existing.g) { existing.g = successor.g; existing.f = existing.g + existing.h; existing.parent = current; } } } } return null; } public static void main(String[] args) { State start = new State(3, 3, 0, 0, 0, 0, h(3, 3, 0, 0, 0)); List<State> path = aStarSearch(start); if (path == null) { System.out.println("No solution found."); } else { for (State state : path) { System.out.printf("(%d, %d, %d, %d, %d)\n", state.ml, state.cl, state.mr, state.cr, state.boat); } } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值