Nguồn đề bài: http://vn.spoj.com/problems/PCIRCLE/
1. Đề bài PCIRCLE spoj
Một vòng tròn chứa 2*n vòng tròn nhỏ (Xem hình vẽ). Các vòng tròn nhỏ được đánh số từ 1 đến 2*n theo chiều kim đồng hồ. Cần điền các số tự nhiên từ 1 đến 2*n mỗi số vào một vòng tròn nhỏ sao cho tổng của hai số trên hai vòng tròn nhỏ liên tiếp là số nguyên tố. Số điền ở vòng tròn nhỏ 1 luôn là số 1.
Input
Số nguyên dương n ( 1 < n < 10 ) .
Output
Dòng đầu tiên ghi ra số k là số cách tìm được.
K dòng tiếp theo mỗi dòng ghi ra 1 cách điền các số vào các vòng tròn nhỏ. Cách điền nào có thứ tự từ điển nhỏ hơn thì xếp trước. Nếu K > 10000 thì chỉ cần ghi ra 10000 cách đầu tiên.
Ví dụ
Input:
4
Output:
4
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
2. Hướng dẫn PCIRCLE spoj
– Viết sẳn thủ tục sàng số nguyên tố
– Áp dụng thuật toán quay lui để chọn các số, kiểm tra điều kiện dựa trên mảng sàng SNT.
– Vì N<10 nên có thể tính trước kết quả K và bỏ vào mảng hằng. chỉ việc xuất ra. Giúp tiết kiệm được bộ nhớ và thời gian khi quay lui.
3. code tham khảo PCIRCLE spoj
const fi=''; fo=''; nmax=10; type data=longint; var f:text; SNT:array[1..50] of boolean; n:data; DD:array[1..nmax*2] of boolean; KQ:array[1..nmax*2] of byte; sl:data; LUUTRU:array[1..16000020] of byte; spt,k:longint; procedure sangnt; var i,j:data; begin fillchar(snt,sizeof(snt),true); i:=2; snt[1]:=false; while i<=sqrt(50) do begin while snt[i]=false do inc(i); for j:=2 to 50 div i do snt[i*j]:=false; inc(i); end; end; procedure init; begin fillchar(dd,sizeof(dd),false); dd[1]:=true; sl:=1; kq[1]:=1; spt:=0; k:=0; end; procedure xuli; var i:data; begin if not snt[1+kq[sl]] then exit; inc(k); for i:=1 to sl do begin inc(spt); LUUTRU[spt]:=kq[i]; end; end; procedure try; var j:data; begin if sl=2*n then begin xuli; end else for j:=2 to 2*n do if (not dd[j]) and (SNT[kq[sl]+j]) then begin dd[j]:=true; inc(sl); kq[sl]:=j; try; dd[j]:=false; dec(sl); end; end; procedure xuat; var i,tam:data; begin assign(f,fo); rewrite(f); writeln(f,k); if k>10000 then tam:=10000*2*n else tam:=k*2*n; for i:=1 to tam do begin write(f,luutru[i],' '); if i mod (2*n) = 0 then writeln(f); end; close(f); end; begin assign(f,fi); reset(f); readln(f,n); close(f); SANGNT; init; try; xuat; end.
#include <iostream> #include <fstream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> using namespace std; int n,x[100],dd[100]; bool yes[100][100]; int res[100] = {0, 0, 2, 2, 4, 96, 1024, 2880, 81024, 770144}; int dem = 0; bool kt(int x) { if (x <= 1) return false; for (int i=2;i*i<=x;i++) if (x % i == 0) return false; return true; } void dq(int t) { if (t == n+1) { if (not yes[x[1]][x[n]]) return; dem++; for (int i=1;i<=n;i++) printf("%d ",x[i]); printf("n"); return; } for (int i=1;i<=n;i++) if (dd[i] == 0 and yes[x[t-1]][i]) { x[t] = i; dd[i] = 1; dq(t+1); if (dem == 10000) return; dd[i] = 0; } } int main() { scanf("%d",&n); printf("%dn",res[n]); n *= 2; for (int i=1;i<=n;i++) for (int j=i;j<=n;j++) { yes[i][j] = kt(i+j); yes[j][i] = yes[i][j]; } x[1] = 1; dd[1] = 1; dq(2); return 0; }
#include <iostream> #include <fstream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cmath> using namespace std; int n,x[100],dd[100],res; bool yes[100][100]; bool kt(int x) { if (x <= 1) return false; for (int i=2;i*i<=x;i++) if (x % i == 0) return false; return true; } void dq(int t) { if (t == n+1) { if (yes[x[1]][x[n]]) res++; return; } for (int i=1;i<=n;i++) if (dd[i] == 0 and yes[x[t-1]][i]) { x[t] = i; dd[i] = 1; dq(t+1); dd[i] = 0; } } int main() { scanf("%d",&n); n *= 2; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) yes[i][j] = kt(i+j); x[1] = 1; dd[1] = 1; dq(2); printf("%d",res); return 0; }