谁养鱼(三):如何让计算机认识线索

谁养鱼问题中给出了15条线索,如何让计算机识别这些线索,并作出正确的判断呢?

因为房子的顺序是固定,给它们编号1、2、3、4、5。每个房子都有五种类型的属性,分别是颜色、国籍、饮料、宠物、香烟,并且不同的房子之间相同类型的属性是不同的。

通过观察可以发现,线索可以分为三类:固定线索,绑定线索和相邻线索。固定线索指的将某个属性固定在某个序号的房子,比如线索8和线索9,分别将牛奶固定在中间房子,将挪威人固定在第一个房子;绑定线索指的是,如果房子A具有属性B,那么也有属性C,比如线索2,瑞典人和狗这两个属性是绑定的;相邻线索指的是两个属性位于相邻的房子里,这种相邻可以是左相邻、右相邻或者左右相邻(简称为相邻),比如线索4,绿色相对于白色是左相邻关系,而线索10是左右相邻。

Solution类是用来表示一个可能解的,包含了五个房子的全部属性的一种排列。为了表示这三种不同的线索,分别设计了FixedClue、BindClue和AdjacentClue类,它们都是Clue的子类,并都有一个重写的方法match,用来检查一个Solution是否满足这个线索。

public abstract class Clue {

	public abstract boolean match(Solution solution);
	
}
public class FixedClue extends Clue{

	/*固定的房间编号*/
	int seat;
	Attribute attr;
	
	@Override
	public boolean match(Solution solution) {		
		/*获取此Solution第seat个房子*/
		House house = solution.get(seat-1);
		/*获取该房子和attr同类型的属性,并比较*/
		if(attr==(house.get(attr.getType().getId()-1))){			
			return true;
		}
		return false;
	}

	public FixedClue(int seat, Attribute attr){
		this.seat = seat;
		this.attr = attr;
	}
}
public class AdjacentClue extends Clue{

	Attribute attr1;
	Attribute attr2;
	int dir;//attr2相对attr1的位置,负数为左相邻,正数为右相邻,0为相邻
	@Override
	public boolean match(Solution solution) {		
		int seat1=0, seat2=0;
		/*获取该Solution具有属性attr1和attr2的房子的位置*/
		for(int i=0; i<solution.size(); ++i){		
			/*获取此Solution第seat个房子*/
			House house = solution.get(i);
			if(house.get(attr1.getType().getId()-1)==attr1)
				seat1=i+1;
			if(house.get(attr2.getType().getId()-1)==attr2)
				seat2=i+1;	
			if(seat1!=0&&seat2!=0)
				break;
		}
		/*比较两个位置的关系*/
		if(dir==0){
			if(seat1-seat2==1 ||seat1-seat2==-1){				
				return true;
			}
		}else if(dir==seat2-seat1){			
			return true;
		}
		return false;
	}

	public AdjacentClue(Attribute attr1, Attribute attr2, int dir){
		this.attr1 = attr1;
		this.attr2 = attr2;
		this.dir = dir;
	}
}
public class BindClue extends Clue{

	Attribute attr1;
	Attribute attr2;
	@Override
	public boolean match(Solution solution) {		
		Iterator<House> iter = solution.iterator();
		/*遍历五个房子,看是否存在房子同时具有属性attr1和attr2*/
		while(iter.hasNext()){
			House house = iter.next();
			if(attr1==(house.get(attr1.getType().getId()-1)) && 
			attr2==(house.get(attr2.getType().getId()-1))){				
				return true;
			}
		}
		return false;
	}

	public BindClue(Attribute attr1, Attribute attr2){
		this.attr1 = attr1;
		this.attr2 = attr2;
	}
}
在Solution类初始化的时候,添加所有的线索到一个ArrayList对象中,每个Solution对象提供一个getMatches接口返回匹配了多少个线索。
import java.util.ArrayList;
import java.util.Iterator;

public class Solution extends ArrayList<House>{
 	
	public static ArrayList<Clue> clues=new ArrayList<Clue>();
	int matches=0;
	
	static{
		clues.add(new BindClue(Attribute.Red, Attribute.Britain));
		clues.add(new BindClue(Attribute.Sweden, Attribute.Dog));
		clues.add(new BindClue(Attribute.Denmark, Attribute.Tea));
		clues.add(new BindClue(Attribute.Green, Attribute.Coffee));
		clues.add(new BindClue(Attribute.Bird, Attribute.PallMall));
		clues.add(new BindClue(Attribute.Yellow, Attribute.Dunhill));
		clues.add(new BindClue(Attribute.Beer, Attribute.BlueMaster));
		clues.add(new BindClue(Attribute.Germany, Attribute.Prince));
		
		clues.add(new FixedClue(3, Attribute.Milk));
		clues.add(new FixedClue(1, Attribute.Norway));
		
		clues.add(new AdjacentClue(Attribute.White, Attribute.Green, -1));
		clues.add(new AdjacentClue(Attribute.Cat, Attribute.Blends, 0));
		clues.add(new AdjacentClue(Attribute.Horse, Attribute.Dunhill, 0));
		clues.add(new AdjacentClue(Attribute.Blue, Attribute.Norway, 0));
		clues.add(new AdjacentClue(Attribute.Water, Attribute.Blends, 0));
		
	}
	
	public int getMatches(){
		matches=0;
		Iterator<Clue> iter = clues.iterator();
		while(iter.hasNext()){
			Clue clue = iter.next();
			if(clue.match(this))
				matches++;
		}
		/**/
		if(God.better==null||matches>God.better.matches){
			God.better = (Solution)this.clone();
		}
		return matches;
	}
}
getMatches方法可以作为遗传算法适应度函数的主要组成部分,用来评价个体的生存能力。



posted on 2011-11-25 21:52  OpenNaive  阅读(189)  评论(0编辑  收藏  举报

导航