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.