Tải bản đầy đủ (.docx) (31 trang)

BÁO CÁO THỰC HÀNH TRÍ TUỆ NHÂN TẠO,KHOA CÔNG NGHỆ THÔNG TIN, ĐH BÁCH KHOA ĐÀ NẴNG

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (180.2 KB, 31 trang )

ĐẠI HỌC ĐÀ NẴNG

TRƯỜNG ĐẠI HỌC BÁCH KHOA
KHOA CÔNG NGHỆ THÔNG TIN

----

BÁO CÁO THỰC HÀNH
TRÍ TUỆ NHÂN TẠO

Giáo viên
Sinh viên thực hiện
Lớp
Nhóm

: Võ Đức Hoàng
: NGUYỄN HẢI QUẢNG
: 10T1
: 12B

Đà Nẵng, 10/2013

Đà Nẵng, 05/2009


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

I.
Trò chơi 8 quân cờ (Cờ ta canh):


1. Bài toán:
Tám (8) quân cờ được chỉ ra trong hình, gồm một bảng kích thước 3x3với 8 quân
cờ dược đánh số từ 1 đến 8 và một ô trống. Một quân cờ đứng cạnh ô trống có thể
đivào ô trống. Mục tiêu là luôn luôn tiến tới vị trí các quân cờ như ở trong hình bên
phải (trạng thái đích).
Trạng thái đầu

Trạng thái đích
1

2

3

4

5

6

7

8

Hãy trình bày thuật toán và viết chương trình demo để di chuyển các quân cờ sao
cho số bước di chuyển là thấp nhất (tối ưu). Dữ liệu được đọc từ file là ma trận vuông
3x3.
2. Thuật toán:
Sử dụng một hàm Heuristic để đánh giá độ tốt của trạng thái
Hàm heuristic F(n) = G(n) + H(n)

Trong đó G(n) là phí tổn thực đi từ trạng thái bắt đầu đến trạng thái đang xét
( Số bước biến đổi trạng thái)
H(n) là phí tổn ước lượng từ trạng thái đang xét đến trạng thái đích
( số quân cờ sai vị trí so với trạng thái đích )
Tạo ra 2 mảng Open và Close
Mảng open chứa trạng thái chưa xét và được sắp xếp theo thứ tự lớn dần F(n)
Mảng Close chứa các trạng thái được đưa vào đường đi
Mỗi khi lấy trạng thái nhỏ nhất trong mảng open minOpen bỏ sang mảng close
thì thêm các trạng thái vừa được sinh ra từ trạng thái minOpen vào mảng open rồi sắp
xếp lại theo thứ tự lớn dần F(n)
Cứ như vậy cho đến khi H(n) = 0 ( trạng thái đích )
3. Chương trình:
package javaapplication1;
import java.io.*;
import java.util.*;
public class JavaApplication1
{
static boolean result;
static LinkedList<State> stateQueue;

SVTH: Nguyễn Hải Quảng

Trang 2


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

public static void main(String[] args)

{
result=false;
State startState = new State(null);
State finalState = new State(null);
StateNode.ResetStateNode();
stateQueue = new LinkedList();
loadData(startState);
setfinalState(finalState);
startState.calStateValue();
finalState.calStateValue();
stateQueue.add(startState);
State resultState = find(finalState);
if (resultState!=null)
printResult(resultState);
else
System.out.println("No result!");
}
static void printResult(State st)
{
if (st!=null)
{
printResult(st.parentState);
st.printOut();
}
}
static State find(State finalState)
{
State resultState=null;
System.out.println("calculating...");
while (!stateQueue.isEmpty() && !result)

{
System.out.println(stateQueue.size());
State tmpState = stateQueue.poll();
if (tmpState!=null)
{
if (State.isEqual(tmpState, finalState))
{
result=true;
resultState=tmpState;
}
SVTH: Nguyễn Hải Quảng

Trang 3


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

else
{
StateNode.addNode(tmpState.stateValue());
tmpState.findState();
for (int i=0;istateQueue.add(tmpState.nextState[i]);
}
}
}
return resultState;
}

static void setfinalState(State st)
{
st.arValue[0]=1;
st.arValue[1]=2;
st.arValue[2]=3;
st.arValue[3]=4;
st.arValue[4]=5;
st.arValue[5]=6;
st.arValue[6]=7;
st.arValue[7]=8;
st.arValue[8]=9;
}
static void loadData(State st)
{
File f = new File("input.txt");
FileReader fr=null;
try
{
fr = new FileReader(f);
} catch (FileNotFoundException ex)
{
}
BufferedReader br = new BufferedReader(fr);
for (int i=0;i<9;i++)
{
try
{
st.arValue[i] = br.read()-48;
}
catch (IOException ex)

{
}
}
SVTH: Nguyễn Hải Quảng

Trang 4


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

}
}
//------------------------------------------------------------------------//
package javaapplication1;
public class State
{
int[] arValue;
State parentState;
State[] nextState;
int stateValue;
public int nextStateIndex;
public State(State parent)
{
arValue = new int [9];
parentState=parent;
nextState = new State[4];
nextStateIndex=0;
}

private void addNextState(State st)
{
nextState[nextStateIndex] = st;
nextStateIndex++;
}
public void findState()
{
int zeropos=0;
while (arValue[zeropos]!=9) zeropos++;
int i,j;
i=zeropos/3;
j=zeropos%3;
if (i>0)
{
State newState = new State(this);
copyState(this, newState);
newState.swap((i*3+j), (i-1)*3+j);
newState.calStateValue();
if (!StateNode.nodeExist(newState.stateValue()))
addNextState(newState);
}
if (i<2)
SVTH: Nguyễn Hải Quảng

Trang 5


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng


{
State newState = new State(this);
copyState(this, newState);
newState.swap((i*3+j), (i+1)*3+j);
newState.calStateValue();
if (!StateNode.nodeExist(newState.stateValue()))
addNextState(newState);
}
if (j>0)
{
State newState = new State(this);
copyState(this, newState);
newState.swap((i*3+j-1), i*3+j);
newState.calStateValue();
if (!StateNode.nodeExist(newState.stateValue()))
addNextState(newState);
}
if (j<2)
{
State newState = new State(this);
copyState(this, newState);
newState.swap(i*3+j+1, i*3+j);
newState.calStateValue();
if (!StateNode.nodeExist(newState.stateValue()))
addNextState(newState);
}
}
public void swap(int pos1, int pos2)
{

int tmp;
tmp=arValue[pos1];
arValue[pos1]=arValue[pos2];
arValue[pos2]=tmp;
}
public int stateValue()
{
return stateValue;
}
public void calStateValue()
{
int result=0;
int factor=1;
for (int i=8;i>=0;i--)
SVTH: Nguyễn Hải Quảng

Trang 6


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

{
result+=arValue[i]*factor;
factor*=10;
}
stateValue=result;
}
public static void copyState(State from, State to)

{
System.arraycopy(from.arValue, 0, to.arValue, 0, 9);
}
public static boolean isEqual(State st1, State st2)
{
boolean result;
if (st1==null || st2==null)
result=false;
else
result=(st1.stateValue()==st2.stateValue());
return result;
}
public void printOut()
{
for (int i=0;i<9;i++)
{
if (arValue[i]==9)
System.out.print(" ");
else
System.out.print(arValue[i] + " ");
if ((i+1)%3==0) System.out.println("");
}
System.out.println("");
}
}
//------------------------------------------------------------------------//
package javaapplication1;
public class StateNode
{
public static StateNode firstNode;

public static StateNode lastNode;

SVTH: Nguyễn Hải Quảng

Trang 7


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

int value;
StateNode nextNode;
public StateNode(int vl)
{
value=vl;
nextNode=null;
}
public static void ResetStateNode()
{
firstNode = new StateNode(0);
firstNode.nextNode=null;
}
public static boolean nodeExist(int value)
{
boolean result=false;
StateNode tmpNode = firstNode;
while (tmpNode!=null && !result)
{
if (value==tmpNode.value)

result=true;
else
tmpNode = tmpNode.nextNode;
}
return result;
}
public static void addNode(int value)
{
StateNode tmpNode=firstNode;
StateNode preNode=firstNode;
while (tmpNode!=null)
{
preNode=tmpNode;
tmpNode=tmpNode.nextNode;
}
preNode.nextNode = new StateNode(value);
}
}
II.
Trò chơi viết số:
1. Bài toán:
Hai người chơi với nhau trò chơi như sau: với 1 số a đang có sẵn, đến lượt mình
chơi, người đó sẽ viết số a+1 hay 2a với điều kiện số mới viết này không vượt qua số

SVTH: Nguyễn Hải Quảng

Trang 8


SVTH: Nguyễn Hải Quảng


GVHD: Võ Đức Hoàng

nguyên dương N cho trước. Với số bắt đầu là 1, ai viết được số N trước thì xem như
thắng.
Xem như máy là người đi sau. Trình bày thuật toán và viết chương trình mô tả trò
chơi sao cho khả năng thắng của máy cao. Dữ liệu được đọc từ bàn phím.
2. Thuật toán:
Từ số 1 ban đầu, 2 người chơi lần lượt viết số a + 1 hoặc 2a ai đi đến số N
trước thì sẽ thắng. Với a + 1 và 2a < N
Ta thấy từ số 1 , người đi trước và máy đi sau. Vậy nước đi tiếp theo của người
sẽ là 2
Xét 2 trường hợp :
Trường hợp thứ 1 : N là số lẻ. Ở trường hợp này vì người đi trước số 2.
Vậy máy chỉ cần đi số a + 1 thì sẽ luôn rơi vào vị trí lẻ thì máy luôn luôn thắng. Vì dù
người có đi số a + 1 hoặc 2a thì cũng sẽ đều rơi vào số chẵn. Máy luôn đi số a + 1 thì
tại bước cuối cùng N là số lẻ sẽ là lượt đi của máy.
Trường hợp thứ 2 : N là số chẵn. Vì khi a > N/2 thì chỉ có thể đi a + 1
( Nếu đi 2a sẽ vượt quá N) nên máy muốn thắng thì phải luôn đi vào số chẵn khi a >
N/2. Vậy khi đến lượt máy nếu 2a > N/2 thì máy sẽ đi 2a để chiến thắng. Ngược lại thì
đi a + 1 để giảm khả năng thắng của người ( Nếu đi 2a < N/2 . Đến lượt của người đi
2a sẽ có khả năng > N/2 cao). Ở trường hợp này thì máy không luôn luôn thắng. Vì
nếu người cũng tính được đi vào 2a > N/2 để chiến thắng thì người cũng sẽ làm các
bước tương tự như máy. Nhưng người có lợi thế hơn là từ đầu đã đi vào số chẵn.
3. Chương trình:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Baiso2vietso {

static int n, a = 1;
public static void nhap()
{
BufferedReader
bf
=
new
BufferedReader(new
InputStreamReader(System.in));
System.out.print("Nhập số N: ");
try {
n = Integer.parseInt(bf.readLine());
} catch (NumberFormatException | IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(a!=n)
{
try {
SVTH: Nguyễn Hải Quảng

Trang 9


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

System.out.println("Player :");
int t = Integer.parseInt(bf.readLine());

if(t==2*a||t==a+1) a = t;
else {System.out.println("Số không hợp lệ");continue;}
if(a!=n){
System.out.println("Computer : ");
tinh();
}
else System.out.println("Player win");
} catch (NumberFormatException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void tinh()
{
if(n%2!=0) a++;
else {
if(2*a>n/2&&2*aelse a++;
}
System.out.println(a);
if(a==n) System.out.println("Computer win");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
nhap();
}

}
III. Bài toán phân việc:
1. Bài toán:
Có n chi tiết máy J1, J2, ..., Jncần gia công lần lượt trên 3 máy A, B, Cvới thời gian
hoàn thành tương ứng của 1 chi tiết là T A, TB, TC. Các chi tiết từ J1, J2, ..., Jncó thể gia
công theo thứ tự bất kỳ tuy nhiên một chi tiết J i phải được gia công lần lượt theo thứ
tự trên máy A  máy B  máy C.
Trình bày thuật toán và viết chương trình mô tả sao cho tổng thời gian gia công
hoàn thành n chi tiết là thấp nhất (tối ưu). Dữ liệu được đọc từ file có dạng như sau:
DULIEU.INP
n
//số chi tiết cần gia công
SVTH: Nguyễn Hải Quảng

Trang 10


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

J1A, J2A,...., JnA
//thời gian gia công các chi tiết trên máy A
J1B, J2B,...., JnB
//thời gian gia công các chi tiết trên máy B
J1C, J2C,...., JnC
//thời gian gia công các chi tiết trên máy C
Kết quả xuất ra là thứ tự các công việc
2. Thuật toán:
Bài toán gia công với 3 máy A, B, C.

Đối với bài toán có 2 máy gia công A, B. Thời gian gia công các chi tiết Ji trên
máy A là TAi ( i = 1…n), thời gian gia công các chi tiết Ji trên máy B là TBi ( i = 1…n
). Ta phân các chi tiết làm 2 nhóm.
Nhóm thứ 1 : Có các chi tiết Ji thỏa mãn TAi < TBi.
Nhóm thứ 2 : Có các chi tiết Ji thỏa mãn TAi > TBi.
Các chi tiết Ji có TAi = TBi phân vào nhóm nào cũng được.
Sắp xếp các chi tiết nhóm 1 theo chiều tăng TAi, và sắp xếp các chi tiết nhóm
2 theo chiều giảm TBi.
Nối nhóm 2 vào nhóm 1 ta sẽ có trình tự gia công các chi tiết.
Lịch gia công tối ưu trên 3 máy A, B, C trùng với lịch gia công tối ưu trên 2
máy, ta chia làm 2 máy : máy thứ 1 với thời gian TAi + TBi, máy thứ 2 với thời gian
TBi + TCi. Phân làm 2 nhóm.
Nhóm thứ 1 : Có các chi tiết Ji thỏa mãn TAi + TBi < TBi + TCi
Nhóm thứ 2 : Có các chi tiết Ji thỏa mãn TAi + TBi > TBi + TCi
Các chi tiết Ji có TAi + TBi= TBi + TCi phân vào nhóm nào cũng được.
Sắp xếp các chi tiết nhóm 1 theo chiều tăng TAi, và sắp xếp các chi tiết nhóm
2 theo chiều giảm TBi.
Nối nhóm 2 vào nhóm 1 ta sẽ có trình tự gia công các chi tiết.
3. Chương trình:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Bai3phancong {
private
static int n;
static int[][] array;
static int[] group1, group2;
public static void load() throws IOException

{
try {
File f = new File("input.txt");
SVTH: Nguyễn Hải Quảng

Trang 11


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

FileReader fr = new FileReader(f);
BufferedReader bf = new BufferedReader(fr);
n = readbuffer(bf);
array = new int[3][n];
for(int i = 0; i < 3; i ++)
for(int j = 0; j < n; j ++)
array[i][j] = readbuffer(bf);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void calculate()
{
group1 = new int[n];
group2 = new int[n];
int i = 0, x = 0, y = 0;
for(i = 0,x = 0, y = 0; i < n; i ++)

{
if(array[0][i] + array[1][i] < array[1][i] + array[2][i])
{
group1[x] = i;
x++;
}
else
{
group2[y] = i;
y++;
}
}
dockinggroup1(x);
dockinggroup2(y);
for(i = 0; i < x; i ++)
System.out.print(group1[i] +"->");
for(i = 0; i < y-1; i ++)
System.out.print(group2[i] + "->");
System.out.println(group2[i]);
}
public static void dockinggroup1(int count)
{
int temp;
for(int i = 0; i < count; i ++)
for(int j = i + 1; j < count; j ++)
SVTH: Nguyễn Hải Quảng

Trang 12



SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

if(group1[i]>group1[j]){
temp = group1[i];
group1[i] = group1[j];
group1[j] = temp;
}
}
public static void dockinggroup2(int count)
{
int temp;
for(int i = 0; i < count; i ++)
for(int j = i + 1; j < count; j ++)
if(group2[i]temp = group2[i];
group2[i] = group2[j];
group2[j] = temp;
}
}
public static int readbuffer(BufferedReader bf) throws IOException
{
int result = 0;
int i = bf.read();
while (!isNumber(i))
i=bf.read();
do
{
result*=10;

result+=i-48;
i=bf.read();
}
while (isNumber(i));
return result;
}
public static boolean isNumber(int c)
{
return (c>=48&&c<=57);
}
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
load();
calculate();
}
}
SVTH: Nguyễn Hải Quảng

Trang 13


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

IV.
Bài toán người du lịch:
1. Bài toán:
Một người khách du lịch muốn đi thăm n thành phố được đánh số từ 1 n và quay
lại thành phố xuất phát. Mạng lưới giao thông giữa n thành phố này là hai chiều và

được cho bởi ma trận A[i,j] trong đó A[i,j]=1 nếu có đường đi từ thành phố i đến thành
phố j, A[i,j]=0 trong trường hợp ngược lại.
Hãy thiết lập lộ trình cho người khách hay thông báo không tồn tại lời giải. Dữ liệu
được đọc từ file có dạng như sau:
DULIEU.INP
Dòng 1: Ghi số nguyên n (n<=20).
Dòng i+1 (1<=i<=n) ghi n số nguyên không âm (0 hoặc 1).
Kết quả xuất ra chu trình đường đi. (Chu trình HAMILTON)
2. Thuật toán:
3. Chương trình:
V.
Bài toán hệ thống dây điện:
1. Bài toán:
Một công ty cần thay toàn bộ hệ thống dây điện cho N phòng làm việc. Cho biết sơ
đồ mạng lưới điện hiện có của n căn phòng được biểu diễn bằng ma trận A[i,j] trong
đó A[i,j] chính là độ dài của dây điện nối giữa 2 phòng i và j (A[i,j]=A[j,i], A[i,j]=0
nếu không có (không thể) dây nối giữa phòng i và j). Hãy lập trình tính độ dài của dây
dẫn cần sử dụng sao cho cả N phòng dều có điện và số lượng này là ít nhất.
Dữ liệu được đọc từ file có N+1 dòng dạng như sau: DULIEU.INP
Dòng 1: Ghi số nguyên N.
Dòng i+1 (1<=i<=N) ghi N số nguyên A[i,1] A[i,2] .........A[i,N].
Các số ghi trên 1 dòng cách nhau ít nhất 1 dấu cách.
Kết quả xuất ra màn hình cách nối và tổng độ dài nhỏ nhất.
2. Thuật toán:
3. Chương trình:
VI. Trò chơi đoán số:
1. Bài toán:
Cậu bé nghĩ ra 1 số (Gọi là S) gồm bỗn chữ số (không nhất thiết khác nhau) trong
sáu chữ số từu 1 đến 6. Để tìm số đó máy lần lượt đưa ra các số dự đoán (gọi là M),
mỗi số gồm 4 chữ số không nhất thiết khác nhau. Với mỗi lần dự đoán, máy nhận được

2 câu trả lời của cậ bé cho 2 câu hỏi sau.
+ Có bao nhiêu chữ số trong M là chữ số trong S nhưng vị trí xuất hiện của mỗi
chữ số đó là sai?
+ Có bao nhiêu chữ số trong M là chữ số trong S và đồng thời vị trí xuất hiện của
mỗi chữ số đều đúng?
Yêu cầu: Hãy hiện lên màn hình các số máy dự đoán và nói mỗi số đó nhận 2
câu trả lời từ bàn phím của cậu bé cho đến khi được số đúng như cậu bé nghĩ. (Số lần
dự đoán không quá 6 lần).
SVTH: Nguyễn Hải Quảng

Trang 14


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

Ví dụ: Số cần tìm là 5436
1234
Đúng số - Đúng vị trí : 1
Đúng số - Sai vị trí : 1
2156
Đúng số - Đúng vị trí : 1
Đúng số - Sai vị trí : 1
1416
Đúng số - Đúng vị trí : 2
Đúng số - Sai vị trí : 0
5436
Đúng số - Đúng vị trí : 4
Đúng số - Sai vị trí : 0

Chọn đúng số
2. Thuật toán:
3. Chương trình:
VII. Chia quà:
1. Bài toán:
Trong ngày sinh nhật Tom và Jerry nhận được N đồ chơi (N<=40). Trên đồ chơi i
có giá tiền là Xi. Hai anh em quyết định mỗi người phải có trách nhiệm bảo quản 1
phần số quà và phân chia sao cho chênh lệch tổng giá trị tiền đồ chơi mà mỗi người
phải bảo quản là ít nhất. Hãy giúp Tom bà Jerry phân chia trách nhiệm. Dữ liệu đọc từ
file text có dạng sau:
Dòng 1 : ghi số nguyên dương N.
Dòng 2 : Ghi N số nguyên dương tương ứng với giá trị N đồ vật.
2. Thuật toán:
3. Chương trình:
VIII. Tô màu bản đồ:
1. Bài toán:
Có 1 bản đồ có N nước. Mỗi nước được tô 1 màu để phân biệt. Các nước liền kề
nhau không được tô cùng màu với nhau. Hãy xác định số màu tối thiểu để tô bản đồ
sao cho các miền kề nhau không được tô cùng màu.
 File dữ liệu đầu vào: GRAPH.INP có cấu trúc
n
m
(n đỉnh:1,2,...,n; m là số cạnh)
x1
y1
(danh sách m cạnh)
x2
y2
....
xm

ym
................
 File kết quả: COLOR.OUT
VERTEX: 1
2
...
n
SVTH: Nguyễn Hải Quảng

Trang 15


SVTH: Nguyễn Hải Quảng
COLOR:
c1
c2
...
 Ví dụ:
GRAPH.INP
COLOR.OUT
10
18
VERTEX: 1 2
1
2
COLOR: 23 2111
1
4
1
5

1
8
2
3
2
5
2
6
3
5
3
6
3
8
4
7
5
7
5
8
5
9
6
9
6
10
8
9
9
10

--------------5
5
VERTEX:
1
2
COLOR:
2
3
3
4
4
5
5
1

GVHD: Võ Đức Hoàng
cn
3456 78910
2323

1
1

2
2

3
1

4

2

5
3

2. Thuật toán:

Bài toán tô màu đồ thị được mô hình hóa từ bài toán thiết kế hệ thống đèn
giao thông tại một giao lộ.
Nếu đề bài cho là một đồ thị nhỏ,đơn giản thì ta cố thử theo mọi phương
án để có thể đi đến một lời giải tối ưu.Nhưng đối với bài toán lớn,phức tạp thì
cách làm bài toán này sẽ tốn rất nhiều thời gian và có thể không tìm được lời
giải,trên thực tế thì khó có thể chấp nhận được.
Vì vậy cần có giải pháp tối ưu hơn.Trong đó tiêu biểu là giải thuật
heuristic hay người ta vẫn gọi la thuật toán “háu ăn” (Greedy Algorithm).Một
giải thuật heuristic hợp lý đối với bài toán tô màu cho đồ thị được mô tả như

SVTH: Nguyễn Hải Quảng

Trang 16


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

sau: Đầu tiên ta cố tô màu cho các đỉnh nhiều hết mức có thể bằng một màu.Với
các đỉnh còn lại (chưa tô) lại làm hết mức với màu thứ 2 và cứ như thế.
Để tô màu cho các đỉnh với màu mới,ta làm như sau:
1.Chọn một đỉnh chưa được tô màu nào đó và tô cho nó màu mới.

2.Tìm trong danh sách các đỉnh chưa được tô màu,với mỗi đỉnh đó
ta xác định xem có một cung nào nối nó với một đỉnh đã được tô bằng màu mới
chưa.Nếu chưa có thì tô đỉnh đó bằng màu mới.
Cách tiếp cận này được gọi là “háu ăn” vì nó thực hiện tô màu một
đỉnh nào đó mà nó có thể tô được,không hề chú ý đến tình thế bất lợi có thể xuất
hiện khi làm điều đó.
3. Chương trình:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
publicclass ToMau
{
Dinh cacDinh[];
int soDinh;
public ToMau()
{
cacDinh =new Dinh[soDinh];
}
publicvoid TaoDoThi()
{
try
{
File inputFile = new File("E:\\input.txt");
FileInputStream fis = new FileInputStream(inputFile);
int c=0;
int i=0,j=0;
int tam=0;

c=fis.read();
soDinh=c-48;
System.out.println("So Dinh Cua Do Thi: "+soDinh);
this.cacDinh=new Dinh[soDinh];
while ((c = fis.read()) != -1)
{
SVTH: Nguyễn Hải Quảng

Trang 17


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

if((c!=13)&&(c!=10)&&(c!=32))
{
c=c-48;
if(i{
cacDinh[i]=new Dinh();
cacDinh[i].viTri=i+1;
cacDinh[i].dinhKe.soDinhKe=c;
cacDinh[i].dinhKe.tenDinhKe=newint[c];
j=0;
while((j{
tam=fis.read();
if((tam!=13)&&(tam!=10)&&(tam!=32))
{

tam=tam-48;
if(j{
cacDinh[i].dinhKe.tenDinhKe[j]=tam;
j++;
}
}

}

}
i++;

}

}
fis.close();
} catch (FileNotFoundException e) {
System.err.println("FileStreamsTest: " + e);
} catch (IOException e) {
System.err.println("FileStreamsTest: " + e);
}

}
public
{

void CamMau(Dinh dinh)
int tam1=0, tam2=0;
for (int i = 0; i < dinh.dinhKe.soDinhKe; i++)

{
//Lay chi so cuadinhkevoidinh
tam1 =dinh.dinhKe.tenDinhKe[i]-1;
tam2 = cacDinh[tam1].soMauCam++;

SVTH: Nguyễn Hải Quảng

Trang 18


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

cacDinh[tam1].cacMauCam[tam2] = dinh.mauDaTo;
}
}
publicboolean KiemTraMauCam(Dinh dinh, int mau)
{
for (int i = 0; i < dinh.soMauCam; i++)
{
if (dinh.cacMauCam[i] == mau)
returntrue;
}
returnfalse;
}
publicvoid ThuatGiaiToMau()
{
int dem=0,somau=1;
while (dem < soDinh)

{
for (int i = 0; i < soDinh; i++)

== false))

{
if ((cacDinh[i].mauDaTo == 0) &&(KiemTraMauCam(cacDinh[i], somau)
{

somau))== false)

cacDinh[i].mauDaTo = somau;
dem++;
CamMau(cacDinh[i]);

for (int j = 0; j < soDinh; j++)
{
int co=0;
for(int k=0;k{
if (j+1 ==cacDinh[i].dinhKe.tenDinhKe[k])
{
co = 1;
break;
}
}
if (co == 0 && cacDinh[j].mauDaTo ==0)
{
if
((KiemTraMauCam(cacDinh[j],

{

SVTH: Nguyễn Hải Quảng

Trang 19


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng
cacDinh[j].mauDaTo = somau;
dem++;
CamMau(cacDinh[j]);
}

}
}
else

}

somau++;
dem++;

}

}
for(int i=0;i{
System.out.println("Dinh

"+cacDinh[i].mauDaTo);
}

"+(i+1)+"

Co

Mau

}
publicvoid Luu()
{
try{
File outputFile = new File("E:\\output.txt");
FileWriter f=new FileWriter(outputFile);
for(int i=0;i{
f.write("Dinh"+(i+1));
f.write("Co Mau:"+cacDinh[i].mauDaTo);
f.write("\n");
}
f.close();
}
catch (FileNotFoundException e) {
System.err.println("FileStreamsTest: " + e);
}
catch (IOException e) {
System.err.println("FileStreamsTest: " + e);
}
}

publicstaticvoid main(String []arg)
{
ToMau toMau=new ToMau();
toMau.TaoDoThi();
toMau.ThuatGiaiToMau();
toMau.Luu();
}
SVTH: Nguyễn Hải Quảng

Trang 20


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

}
IX. Người lái đò:
1. Bài toán:
Viết chương trình mô phỏng bài toán người lái đò (có thể có giao diện đồ họa). Bài
toán phát biểu như sau:
Tại bến sông nọ có bắp cải, sói và dê muốn bác lái đò chở qua sông. Biết rằng tại
một thời điểm thuyền của bác lái đò chỉ chở tối đa được 2 khách. Nếu sói và dê đứng
riêng với nhau (không có mặt bác lái đò và bắp cải) thì sói sẽ ăn thịt dê. Nếu dê và bắp
cải đứng riêng với nhau (không có mặt bác lái đò và sói) thì dê sẽ ăn bắp cải.
Ký hiệu bờ sông mà sói, dê, bắp cải và bác lái đò đang đứng là 1, bờ sông bên kia
là 2. Hãy viết chương trình giải quyết bài toán trên.
2. Thuật toán:
- Bài toán có hai trạng thái:
 Trạng thái bờ trái {Dê, Bắp cải, Sói, Người lái đò}.

 Trạng thái bờ phải {Dê, Bắp cải, Sói, Người lái đò}.
- Mỗi trạng thái có một cách thay đổi:
 Trạng thái bờ trái: Di chuyển qua bờ phải.
 Trạng thái bờ phải: Di chuyển về lại bờ trái.
- Mỗi cách thay đổi trạng thái sẽ có cách thay đổi cụ thể:
 Di chuyển thầy tu hoặc quỷ qua bờ phải có ba trường hợp thay đổi
trạng thái:
 Đưa 2 thầy tu qua bờ phải.
 Đưa 2 quỷ qua bờ phải.
 Đưa 1 thầy tu hoặc 1 quỷ qua bờ phải.
 Di chuyển thầy tu hoặc quỷ về lại bờ trái có hai trường hợp thay đổi
trạng thái:
 Đưa 1 quỷ về bờ trái.
 Đưa 1 thầy tu và 1 quỷ về bờ trái.
- Mỗi lần thực hiện thay đổi trạng thái thì cần phải kiểm tra trạng thái đó có
thay đổi đúng hay không?
 Số thầy tu phải lớn hơn bằng số quỷ hoặc số thầy tu bằng 0 ở mỗi trạng
thái.
- Như vậy, bài toán này sẽ thực hiện theo thuật toán Best-first Search để tìm
ra trạng thái cuối cùng cần tìm.
3. Chương trình:
#include <conio.h>
#include <iostream>
using namespace std;
int brinkLeft[4];
int brinkRight[4];
SVTH: Nguyễn Hải Quảng

Trang 21



SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

static int count = 0;
void init() {
//
Initiallize Goat = 1, Cabbage = 2, Wolf = 3, Ferryman = 4.
// Goat, Cabbage and Wolf are in brink left.
brinkLeft[0] = 1;
brinkLeft[1] = 2;
brinkLeft[2] = 3;
brinkLeft[3] = 4;
brinkRight[0] = 0;
brinkRight[1] = 0;
brinkRight[2] = 0;
brinkRight[3] = 0;
}
bool check(int a, int b, int c, int d) {
if((a == 1 && b == 2 && c == 3 && d == 0)
|| (a == 1 && b == 2 && c == 0 && d == 4)
|| (a == 1 && b == 0 && c == 3 && d == 4)
|| (a == 0 && b == 2 && c == 3 && d == 4)
|| (a == 0 && b == 2 && c == 3 && d == 0)
|| (a == 1 && b == 0 && c == 0 && d == 4)
|| (a == 0 && b == 2 && c == 0 && d == 4)
|| (a == 0 && b == 0 && c == 3 && d == 4)
|| (a == 1 && b == 0 && c == 0 && d == 0)
|| (a == 0 && b == 2 && c == 0 && d == 0)

|| (a == 0 && b == 0 && c == 3 && d == 0 && count == 2)
|| (a == 0 && b == 0 && c == 0 && d == 0)
|| (a == 1 && b == 2 && c == 3 && d == 4))
return true;
return false;
}
void brinkLeftToRight() {
//
Left to right have three case: Goat (1) or Cabbage (2) or Wolf (3) + Ferryman
(4) pass over.
int tempLeft[4], tempRight[4];
for(int i = 0; i < 3; i++) {
tempLeft[0] = brinkLeft[0]; tempLeft[1] = brinkLeft[1] ;
tempLeft[2] = brinkLeft[2]; tempLeft[3] = brinkLeft[3];
tempRight[0] = brinkRight[0]; tempRight[1] = brinkRight[1];
tempRight[2] = brinkRight[2]; tempRight[3] = brinkRight[3];
switch(i) {
//
Goat + Ferryman pass over.
SVTH: Nguyễn Hải Quảng

Trang 22


SVTH: Nguyễn Hải Quảng

//

//


GVHD: Võ Đức Hoàng

case 0: {
tempLeft[0] -= 1; tempRight[0] += 1;
tempLeft[3] -= 4; tempRight[3] += 4;
break;
}
Cabbage + Ferryman pass over.
case 1: {
tempLeft[1] -= 2; tempRight[1] += 2;
tempLeft[3] -= 4; tempRight[3] += 4;
break;
}
Wolf + Ferryman pass over.
case 2: {
tempLeft[2] -= 3; tempRight[2] += 3;
tempLeft[3] -= 4; tempRight[3] += 4;
break;
}
default: break;

}
if(check(tempLeft[0], tempLeft[1], tempLeft[2], tempLeft[3])
&& check(tempRight[0], tempRight[1], tempRight[2], tempRight[3])) {
count++;
brinkLeft[0] = tempLeft[0]; brinkLeft[1] = tempLeft[1];
brinkLeft[2] = tempLeft[2]; brinkLeft[3] = tempLeft[3];
brinkRight[0] = tempRight[0]; brinkRight[1] = tempRight[1];
brinkRight[2] = tempRight[2]; brinkRight[3] = tempRight[3];
switch(i) {

case 0: {
cout << count << ". Goat pass over: Left --->>>
Right." << endl;
break;
}
case 1: {
cout << count << ". Cabbage pass over: Left
--->>> Right." << endl;
break;
}
case 2: {
cout << count << ". Wolf pass over: Left --->>>
Right." << endl;
break;
}
default: break;
}
SVTH: Nguyễn Hải Quảng

Trang 23


SVTH: Nguyễn Hải Quảng

GVHD: Võ Đức Hoàng

break;
}

}


}
void brinkRightToLeft() {
//
Right to left have four case: Ferryman (4) or Goat (1) or Cabbage (2) or Wolf
(3) comeback again.
int tempLeft[4], tempRight[4];
for(int i = 0; i < 4; i++) {
tempLeft[0] = brinkLeft[0]; tempLeft[1] = brinkLeft[1] ;
tempLeft[2] = brinkLeft[2]; tempLeft[3] = brinkLeft[3];
tempRight[0] = brinkRight[0]; tempRight[1] = brinkRight[1];
tempRight[2] = brinkRight[2]; tempRight[3] = brinkRight[3];
switch(i) {
//
Ferryman comeback again.
case 0: {
tempLeft[3] += 4; tempRight[3] -= 4;
break;
}
//
Goat comeback again.
case 1: {
tempLeft[0] += 1; tempRight[0] -= 1;
tempLeft[3] += 4; tempRight[3] -= 4;
break;
}
//
Cabbage comeback again.
case 2: {
tempLeft[1] += 2; tempRight[1] -= 2;

tempLeft[3] += 4; tempRight[3] -= 4;
break;
}
//
Wolf comeback again.
case 3: {
tempLeft[2] += 3; tempRight[2] -= 3;
tempLeft[3] += 4; tempRight[3] -= 4;
break;
}
default: break;
}
if(check(tempLeft[0], tempLeft[1], tempLeft[2], tempLeft[3])
&& check(tempRight[0], tempRight[1], tempRight[2], tempRight[3])) {
count++;
brinkLeft[0] = tempLeft[0]; brinkLeft[1] = tempLeft[1];
SVTH: Nguyễn Hải Quảng

Trang 24


SVTH: Nguyễn Hải Quảng

--->>> Left." << endl;

GVHD: Võ Đức Hoàng

brinkLeft[2] = tempLeft[2]; brinkLeft[3] = tempLeft[3];
brinkRight[0] = tempRight[0]; brinkRight[1] = tempRight[1];
brinkRight[2] = tempRight[2]; brinkRight[3] = tempRight[3];

switch(i) {
case 0: {
cout << count << ". Ferryman comeback: Right
break;

}
case 1: {
cout << count << ". Goat comeback:
--->>> Left." << endl;

Right

break;
}
case 2: {
cout << count << ". Cabbage comeback:

--->>> Left." << endl;

Right

break;

}
case 3: {
cout << count << ". Wolf comeback:
--->>> Left." << endl;

Right


break;
}
default: break;
}
break;

}

}

}
void display() {
for(int i = 0; i < 4; i++)
cout << brinkLeft[i] << " ";
cout << endl;
for(int i = 0; i < 4; i++)
cout << brinkRight[i] << " ";
cout << endl;
}
void passOver() {
while(1) {
display();
brinkLeftToRight();
SVTH: Nguyễn Hải Quảng

Trang 25


×