QBSELECT Spoj – VOI06 Chọn ô

Nguồn đề bài: http://vn.spoj.com/problems/QBSELECT/

1. Đề bài QBSELECT Spoj

Cho một bảng hình chữ nhật kích thước 4×n ô vuông. Các dòng được đánh số từ 1 đến 4, từ trên xuống dưới, các cột được đánh số từ 1 đến n từ trái qua phải.

Ô nằm trên giao của dòng i và cột j được gọi là ô (i,j). Trên mỗi ô (i,j) có ghi một số nguyên aij , i =1, 2, 3, 4; j =1, 2, …, n. Một cách chọn ô là việc xác định một tập con khác rỗng S của tập tất cả các ô của bảng sao cho không có hai ô nào trong S có chung cạnh. Các ô trong tập S được gọi là ô được chọn, tổng các số trong các ô được chọn được gọi là trọng lượng của cách chọn. Tìm cách chọn sao cho trọng lượng là lớn nhất.

Ví dụ: Xét bảng với n=3 trong hình vẽ dưới đây:

Cách chọn cần tìm là tập các ô S = {(3,1), (1,2), (4,2), (3,3)} với trọng lượng 32.

Input

Dòng đầu tiên chứa số nguyên dương n là số cột của bảng.

Cột thứ j trong số n cột tiếp theo chứa 4 số nguyên a1j, a2j, a3j, a4j, hai số liên tiếp cách nhau ít nhất một dấu cách, là 4 số trên cột j của bảng.

Output

Gồm 1 dòng duy nhất là trọng lượng của cách chọn tìm được.

Example

Input:

3

-1 9 3

-4 5 -6

7 8 9

9 7 2

Output:

32

Hạn chế

Trong tất cả các test: n ≤ 10000, |aij| ≤ 30000. Có 50% số lượng test với n ≤ 1000.

2. Gợi ý QBSELECT Spoj

– Các bạn dùng thuật toán Quy Hoạch Động trạng thái:

Gọi F[i,x] là trọng lượng lớn nhất nếu xét từ cột 1 đến cột i và trạng thái của cột i được biểu diễn bằng biến x. Công thức Quy Hoạch Động là:

F[i,x]=Max(F[i-1,x’]+Sum(i,x))

Trong đó:

— x và x’ là trạng thái chọn của hai cột liên tiếp nhau (i và i-1) do đó hai trạng thái phải thỏa mãn điều kiện không có hai ô nào được chọn kề nhau.

— Sum(i,x) là trọng lượng tương ứng với trạng thái chọn x của cột i.

3. Code Tham Khảo QBSELECT Spoj

a. Code Pascal

const
  fi='';
  fo='';
var
  f:text;
  n,j,t:Longint;
  i,k:byte;
  c:array[0..15,0..15]of 0..1;
  a:array[0..4,0..10001]of longint;
  l:array[0..10001,0..15]of longint;

function d(x:byte):longint;
begin
  d:=0;
  if x and 1 = 1 then d:=d+a[1,j];
  if x shr 1 and 1 =1 then d:=d+a[2,j];
  if x shr 2 and 1 =1 then d:=d+a[3,j];
  if x shr 3 and 1 =1 then d:=d+a[4,j];
end;

begin
  for i:=0 to 15 do
    for j:=i to 15 do
      begin
        c[i,j]:=((i and 1) and (i shr 1 and 1))
                or ((i shr 2 and 1) and (i shr 1 and 1))
                or ((i shr 2 and 1) and (i shr 3 and 1))
                or ((j and 1) and (j shr 1 and 1))
                or ((j shr 2 and 1) and (j shr 1 and 1))
                or ((j shr 2 and 1) and (j shr 3 and 1))
                or ((i and j) and 1) or ((i and j)shr 1 and 1)
                or ((i and j)shr 2 and 1) or ((i and j)shr 3 and 1);
        c[j,i]:=c[i,j];
      end;
  assign(f,fi);
  reset(f);
  readln(f,n);
  t:=-50000;
  for i:=1 to 4 do
    begin
      for j:=1 to n do
        begin
          read(f,a[i,j]);
          if a[i,j]>t then t:=a[i,j];
        end;
      readln(f);
    end;
  close(f);

  if t<0 then begin assign(f,fo); rewrite(f); writeln(f,t); close(f); halt; end;

  j:=1;
  for i:=0 to 15 do
    if c[i,0]=0 then l[1,i]:=d(i) else l[1,i]:=0;
  for j:=2 to n do
    for i:=0 to 15 do
      if c[i,0]=1 then l[j,i]:=0 else
      begin
        t:=d(i);
        for k:=0 to 15 do
          if c[i,k]=0 then if l[j,i]<l[j-1,k]+t then l[j,i]:=l[j-1,k]+t;
      end;

  assign(f,fo);
  rewrite(F);
  t:=l[n,0];
  for i:=1 to 15 do if l[n,i]>t then t:=l[n,i];
  writeln(f,t);
  close(f);
end.

b. Code C++

    #include <stdio.h>
    #include <algorithm>

    #define ll long long
    #define maxN 10001
    #define minC -200000000

    using namespace std;

    int n;
    int a[5][maxN], f[16][maxN], fr[9][9];
    bool flag = false;

    int getbit(int k, int x){
        return (x >> (k-1)) & 1;
    }

    void inp(){
        int inmax = minC;
        for (int i = 1; i <= 4; i++)
            for (int j = 1; j <= n; j++){
                scanf("%d", &a[i][j]);
                inmax = max(inmax, a[i][j]);
            }
        if (inmax < 0){
            printf("%d", inmax);
            flag = true;
        }
    }

    int ok(int x, int y){
        int bit[5], elsebit[5];
        for (int v = 1; v <= 4; v++) bit[v] = getbit(v, x);
        for (int v = 1; v <= 4; v++) elsebit[v] = getbit(v, y);
        for (int v = 1; v <= 4; v++)
            if ((bit[v] & elsebit[v]) == 1) return 0;
        return 1;
    }

    int value(int x, int y){
        int bit[5], sum = 0;
        for (int v = 1; v <= 4; v++) bit[v] = getbit(v, x);
        for (int v = 1; v <= 4; v++)
            if (bit[v] == 1) sum += a[v][y];
        return sum;
    }

    int bitmask(){
        int d[] = {0, 1, 2, 4, 5, 8, 9, 10}, res = minC;
        for (int i = 0; i <= 8; i++)
            for (int j = 0; j <= 8; j++) fr[i][j] = ok(d[i], d[j]);
        for (int i = 0; i <= n; i++)
            for (int j = 0; j <= 8; j++){
                int t = minC;
                for (int k = 0; k <= 8; k++)
                    if (fr[j][k] == 1 && f[k][i-1] > t) t = f[k][i-1];
                f[j][i] = t + value(d[j], i);
            }
        for (int i = 0; i <= 8; i++) res = max(res, f[i][n]);
        return res;
    }

    int main(){
        //freopen("SELECT.INP", "r", stdin);
        //freopen("SELECT.OUT", "w", stdout);
        scanf("%d", &n);
        inp();
        if (flag) return 0;
        printf("%d", bitmask());
        return 0;
    }

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 *