VECTOR spoj – Tổng Vector

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

1. Đề bài VECTOR spoj

Trong mặt phẳng tọa độ có N véc tơ. Mỗi một véc tơ được cho bởi hai chỉ số x và y. Tổng của hai véc tơ (xi, yi) và (xj, yj) được định nghĩa là một véc tơ (xi + xj, yi + yj). Bài toán đặt ra là cần chọn một số véc tơ trong N véc tơ đã cho sao cho tổng của các vec tơ đó là véc tơ (U, V).

Yêu cầu: Đếm số cách chọn thoả mãn yêu cầu bài toán đặt ra ở trên.

Input

Dòng thứ nhất ghi số N (0 ≤ N ≤ 30).

N dòng tiếp theo, dòng thứ i ghi các số nguyên xi, yi lần lượt là hai chỉ số của véc tơ thứ i. (|xi|, |yi| ≤ 100).

Dòng cuối cùng ghi số hai số nguyên U V (|U|, |V| ≤ 109).

Output

Gồm một số duy nhất là số cách chọn thoả mãn.

Example

Input:
4
0 0
-1 2
2 5
3 3
2 5

Output:
4

2. Hướng dẫn VECTOR spoj

Nếu duyệt tổ hợp của N Vector thì độ phức tạp thuật toán là O(2^N), với n=30 thì không thể ăn hết điểm của bài này. Vì vậy cần giảm N xuống, thay bằng thuật toán duyệt phân tập (duyệt bằng cách chia đôi tập hợp – trong tập “Một số vấn đề trong tin học” hoặc KCBOOK) :

  • Chia tập hợp thành 2 tập con là A và B.
  • Duyệt tập A dùng mảng F[i,j] để đếm số cách chọn những vector từ A đề được tổng (i, j).
  • Duyệt tiếp tập B, với mỗi tổng (a, b) thu được, ta cộng vào biến Res (Result) theo công thức : Res := Res + f[u-a, v-b];
  • Biến res chính là kết quả bài toán.

3. Code tham khảo VECTOR spoj

* Admin đã bổ sung thêm code mẫu 27/06/2015 

a. Code pascal 1

const
        maxn    =       30;
        maxc    =       3000;
type
        TVector =       record
                x, y    :       longint
        end;
var
        n, u, v,
        res     :       longint;
        vec, t  :       array[0..maxn] of TVector;
        f       :       array[-3000..3000, -3000..3000] of longint;


procedure enter;
var     fi : text;
        i : longint;
begin
        assign(fi, ''); reset(fi);
        readln(fi, n);
        for i:= 1 to n do
        with vec[i] do
                readln(fi, x, y);
        readln(fi, u, v);
        close(fi)
end;

procedure process1(i : longint);
var     j : byte;
begin
        for j:= 0 to 1 do
        begin
                t[i].x:= t[i-1].x;
                t[i].y:= t[i-1].y;
                if j=1 then
                begin
                        t[i].x:= t[i].x + vec[i].x;
                        t[i].y:= t[i].y + vec[i].y
                end;
                if i <= n div 2 then
                        if i < n div 2 then
                                process1(i+1)
                        else    inc(f[t[i].x, t[i].y]);
        end;
end;

procedure process2(i : longint);
var     j : byte;
begin
        for j:= 0 to 1 do
        begin
                t[i].x:= t[i-1].x;
                t[i].y:= t[i-1].y;
                if j=1 then
                begin
                        t[i].x:= t[i].x + vec[i].x;
                        t[i].y:= t[i].y + vec[i].y
                end;
                if i <= n then
                        if i < n then
                                process2(i+1)
                        else    inc(res, f[u-t[i].x, v-t[i].y])
        end
end;


begin
        enter;
        if (u>3000) or (v>3000) then
                writeln(0)
        else    begin
                process1(1);
                with t[n div 2] do
                begin
                        x:= 0; y:= 0
                end;
                process2(n div 2 + 1);
                writeln(res);
        end;
readln
end.

b. Code pascal 2

Code của admin

const   fi='';
        nmax=30;
type    data=longint;
var
        f:text;
        B:array[-3000..3000,-3000..3000] of word;
        ax,ay:array[0..nmax+1] of data;
        uu,vv,n,res:data;

procedure try1(i,u,v:data);
begin
        if i>n div 2 then exit;
        try1(i+1,u+ax[i],v+ay[i]);
        inc(b[u+ax[i],v+ay[i]]);
        try1(i+1,u,v);
end;

procedure try2(i,u,v:data);
begin
        if i>n then exit;
        res:=res+b[uu-(u+ax[i]),vv-(v+ay[i])];
        try2(i+1,u+ax[i],v+ay[i]);
        try2(i+1,u,v);
end;

procedure docfile;
var     i,j:data;
begin
        assign(f,fi); reset(f);
        readln(f,n);
        fillchar(b,sizeof(b),0);
        for i:=1 to n do
                readln(f,ax[i],ay[i]);
        readln(f,uu,vv); b[0,0]:=1;
        close(f);
end;

begin
        docfile;
        try1(1,0,0);
        res:=B[uu,vv];
        try2(n div 2+1,0,0);
        writeln(res);
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 *