Nguồn đề bài: http://vn.spoj.com/problems/KCOLLECT/
1. Đề bài KCOLLECT spoj
Công việc buôn bán dừa của Pirate không mấy khả quan cho lắm, khiến anh đêm ăn không ngon ngày ngủ không yên, chỉ biết chúi đầu vào xem “Rôbô trái cây”. Một ngày nọ, đang nằm ngủ dưới gốc dừa, bỗng một trái dừa rơi vào đầu anh ấy. Cũng giống như Newton, Pirate cũng cầm trái dừa lên, ngắm nghía và… rủa: “Khỉ thật, sao xứ này toàn là dừa thế này!”. Tức điên lên, Pirate quyết trồng thêm các loại trái cây khác vào hòn đảo của mình.
Đến mùa thu hoạch, Pirate đặt hàng một “Rôbô trái cây” để giúp mình hái quả. Khu vườn của Pirate có hình chữ nhật, và được chia thành M x N ô vuông bằng nhau. Trong mỗi ô vuông có một cây thuộc một loại quả khác nhau, đánh số từ 0 đến 9. Không phải vô tình mà chúng được đánh số như vậy, con số đó thể hiện giá trị kinh tế của các loại cây.
Tuy nhiên, nhìn mặt con Rôbô trái cây này có vẻ ngu ngu nên trong lần đầu tiên thử việc, Pirate muốn test AI của nó. Cụ thể là Rôbô phải tuân theo các quy định sau:
a. Tại mỗi ô, Rôbô chỉ có thể đi sang hướng đông hoặc hướng nam sang ô kề cạnh.
b. Có một số ô đặc biệt mà tại đó Rôbô có thể đi được thêm hướng tây hoặc hướng bắc sang ô kề cạnh (chỉ một trong hai).
c. Rôbô không được đi vào những ô có cây dừa (Pirate căm thù dừa).
d. Rôbô được đi qua một ô nhiều lần. Khi đi qua một ô, Rôbô phải hái hết quả ở cây trong ô đó. Lợi nhuận thu được sẽ bằng chỉ số của loại cây vừa được thu hái. Và sau này, không thể đạt thêm lợi nhuận gì từ ô đó nữa.
Xuất phát từ ô ở góc tây bắc của khu vườn, hãy giúp Rôbô trái cây xác định hành trình để đạt được lợi nhuận tối đa.

Input
- Dòng thứ nhất: ghi hai số nguyên M và N – kích thước của khu vườn.
- M dòng tiếp theo: mỗi dòng ghi N kí tự liên tiếp nhau mô tả khu vườn:
+ ‘0’ – ‘9’: các loại trái cây;
+ ‘#’: cây dừa;
+ ‘W’: được quyền đi theo hướng tây;
+ ‘N’: được quyền đi theo hướng bắc.
Output
- Ghi một số nguyên duy nhất là lợi nhuận tối đa đạt được.
Giới hạn
- Trong mọi test, 1 ≤ M, N ≤ 100.
- 60% số test có 1 ≤ M, N ≤ 20.
Example
Input:
2 3
264
3WW
Output:
15
Giải thích: Rôbô sẽ đi theo hành trình như sau (1, 1) -> (1, 2) -> (1, 3) -> (2, 3) -> (2, 2) -> (2, 1) (ô (i, j) là ô ở dòng i và cột j). Tổng lợi nhuận sẽ là 2 + 6 + 4 + 3 = 15.
2. Hướng dẫn Kcollect spoj
Coi mỗi ô là một đỉnh, tìm số thành phần liên thông mạnh, đánh dấu những ô thuộc thành phần liên thông mạnh đó, coi mỗi thành phần liên thông mạnh là một đỉnh của đồ thị mới, định chiều đồ thị, vì đây là đồ thị có hướng ko chu trình nên ta tìm đường đi dài nhất bằng sắp xếp topo để đánh số đồ thị, sau đó áp dụng quy hoạch động tìm đường đi dài nhất . Có thể tham khảo thêm phần sắp xếp topo trong quyển một số vấn đề đáng chú ý môn tin học để hiểu rõ
3. Code tham khảo Kcollect spoj
uses math;
const fi = 'KCOLLECT.inp';
fo = 'KCOLLECT.out';
max = 1000000;
d : array[1..2] of longint = (0, 1);
c : array[1..2] of longint = (1, 0);
type banghi = record
x, y : longint;
end;
var
s : array[1..100, 1..100] of char;
free : array[1..100, 1..100] of longint ;
number, low : array[1..100,1..100] of longint;
tong , u, v, deg, num , a, q: array[1..max] of longint;
head, f : array[0..max] of longint;
adj : array[1..10000000] of longint;
visited : array[1..max] of boolean;
stack : array[1..max] of banghi;
n, count, componentcount, top, m, id : longint;
procedure readf;
var
i, j : longint;
begin
//assign(input, fi); reset(input);
//assign(output,fo); rewrite(output);
readln(m ,n);
for i := 1 to m do
for j := 1 to n do
if j <> n then read(s[i,j]) else readln(s[i,j]);
end;
procedure init;
begin
fillchar(number, sizeof(number), 0);
fillchar(free, sizeof(free), 0);
top := 0;
count := 0;
componentcount := 0;
end;
procedure push(x, y : longint);
begin
inc(top);
stack[top].x := x;
stack[top].y := y;
end;
function pop : banghi ;
begin
pop := stack[top];
dec(top);
end;
procedure visit(x, y:longint); {tim kiem theo chieu sau bat dau tai u}
var
i , a1, a2 : longint; res : banghi;
begin
inc(count); number[x, y] := count; { danh stt tham u}
low[x, y] := count ; {tam thoi coi u co cung toi u }
push(x, y);
for i := 1 to 2 do
begin
a1 := x + d[i];
a2 := y + c[i];
if (a1 <= m ) and (a2 <= n) and (free[a1, a2] = 0) and (s[a1,a2] <> '#') then
if number[a1, a2] <> 0 then { neu ma v da tham }
low[x, y] := min(low[x, y], number[a1, a2]) {giam low[u] nho nhat co the }
else { neu v chua tham }
begin
visit(a1, a2) ; { tham v }
low[x, y] := min(low[x, y], low[a1, a2]);
end;
end;
if s[x,y] = 'W' then
begin
a1 := x;
a2 := y - 1;
if (a1 >= 1) and (a2 >= 1) and (free[a1,a2] = 0 ) and (s[a1,a2] <> '#') then
if number[a1, a2] <> 0 then { neu ma v da tham }
low[x, y] := min(low[x, y], number[a1, a2]) {giam low[u] nho nhat co the }
else { neu v chua tham }
begin
visit(a1,a2) ; { tham v }
low[x, y] := min(low[x, y], low[a1, a2]);
end;
end;
if s[x,y] = 'N' then
begin
a1 := x - 1;
a2 := y ;
if (a1 >= 1) and (a2 >= 1) and (free[a1,a2] = 0 ) and (s[a1,a2] <> '#') then
if number[a1, a2] <> 0 then { neu ma v da tham }
low[x, y] := min(low[x, y], number[a1, a2]) {giam low[u] nho nhat co the }
else { neu v chua tham }
begin
visit(a1,a2) ; { tham v }
low[x, y] := min(low[x, y], low[a1, a2]);
end;
end;
{ sau khi chay het vong nay ta thay moi dinh thuoc DFS goc u da tham}
if low[x, y] = number[x, y] then { neu u la chot }
begin
inc(componentcount);
repeat
res := pop;
free[res.x, res.y] := componentcount;
if s[res.x, res.y] in ['0'..'9'] then
tong[componentcount] := tong[componentcount] + ord(s[res.x, res.y]) - 48;
until (res.x = x) and (res.y = y)
end;
end
procedure solve;
var
dem, i, j : longint;
begin
for i := 1 to m do
for j := 1 to n do
if (number[i, j] = 0) and (s[i,j] <> '#') then
visit(i, j);
end;
procedure creat;
var
i, j , k, a1, a2, dem : longint;
begin
dem := 0;
for i := 1 to m do
for j := 1 to n do
if s[i,j] <> '#' then
begin
for k := 1 to 2 do
begin
a1 := i + d[k];
a2 := j + c[k];
if (a1 <= m ) and (a2 <= n) and (s[a1,a2] <> '#') then
if (free[i,j] <> free[a1,a2]) then
begin
inc(dem);
u[dem] := free[i,j];
v[dem] := free[a1,a2];
inc(deg[free[i,j]]);
end;
end;
if s[i,j] = 'W' then
begin
a1 := i ;
a2 := j - 1;
if (a1 >= 1) and (a2 >= 1) and (s[a1,a2] <> '#') then
if (free[i,j] <> free[a1,a2]) then
begin
inc(dem);
u[dem] := free[i,j];
v[dem] := free[a1,a2];
inc(deg[free[i,j]]);
end;
end;
if s[i,j] = 'N' then
begin
a1 := i -1 ;
a2 := j ;
if (a1 >= 1) and (a2 >= 1) and (s[a1,a2] <> '#') then
if (free[i,j] <> free[a1,a2]) then
begin
inc(dem);
u[dem] := free[i,j];
v[dem] := free[a1,a2];
inc(deg[free[i,j]]);
end;
end;
end;
head[1] := 1;
for i := 2 to componentcount do
head[i] := head[i-1] + deg[i-1];
for i := 1 to dem do
begin
adj[head[u[i]]] := v[i];
inc(head[u[i]]);
end;
for i := 1 to componentcount do
dec(head[i]);
end;
procedure DFS(u: longint);
var
v : longint;
begin
visited[u] := true;
for v := head[u-1] + 1 to head[u] do
if (not visited[adj[v]]) then
DFS(adj[v]);
num[u] := id;
q[id] := u;
dec(id);
end;
procedure process;
var
u , i, j : longint;
begin
fillchar(visited,sizeof(visited),false);
id := componentcount;
for u:= 1 to componentcount do
if not visited[u] then DFS(u);
m := free[1,1];
fillchar(f, sizeof(f), 255);
f[q[componentcount]] := tong[q[componentcount]];
for i := componentcount - 1 downto 1 do
begin
for j := head[q[i]- 1] + 1 to head[q[i]] do
if f[adj[j]] >-1 then
if f[adj[j]] + tong[q[i]] > f[q[i]] then f[q[i]] := f[adj[j]] + tong[q[i]] ;
if f[q[i]] = -1 then f[q[i]] := tong[q[i]];
if q[i] = m then exit;
end;
end;
BEGIN
readf;
init;
solve;
creat;
process;
write(f[free[1,1]]);
END.