KCOLLECT spoj – Thu hoạch

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.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *