PCIRCLE spoj – Vòng số nguyên tố

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;
}

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 *