HDU ACM 1979的一种解法
1. 题目
题目原文见http://acm.hdu.edu.cn/showproblem.php?pid=1979
2. 数据
2.1. 可逆素数表
int prime_digits_buff[MAX_BUFF][4];
用数组存放可逆素数的4位数。
2.2. 可逆素数标识
int is_reverse_prime[10000];
例如,1192不是可逆素数,因此is_reverse_prime[1192]为0,1193是可逆素数,因此is_reverse_prime[1193]为1。
2.3. 可逆素数索引
typedef struct
{
int count;
int list[MAX_BUFF];
} prime_link_t;
prime_link_t prime_link_buff[10];
按可逆素数的最高位来组织可逆素数的索引表。例如,1193将存放在prime_link_buff[1]中,3911将存放在prime_link_buff[3]中。
2.4. 解矩阵
typedef struct
{
int val[4]; /*矩阵的4个可逆素数*/
int digits[4][4]; /*矩阵的每一位数值*/
} solution_t;
char solution_buff[MAX_SOLUTION][17]; /*矩阵字符串*/
3. 算法
3.1. 主算法
求出1000到9999之间的可逆素数及其总数reverse_prime_count;
建立is_reverse_prime;
建立prime_link_buff;
for (i = 0; i < prime_count; i ++)
{
从 prime_digits_buff[i]取出一个可逆素数;
if(该可逆素数的4位数在prime_link_buff中的count都大于0)
{
根据这4位数通过组合循环从prime_link_buff中找出可逆素数来构造解矩阵,并在构造后把符合条件的矩阵存入solution_buff;
}
}
对solution_buff排序;
输出solution_buff;
3.2. 构造解矩阵算法
以一个可逆素数的4位数为第1位数,通过递归来寻找4个可逆素数。例如,对于9133,可找到第1位分别是9、1、3、3的4个数9173、1559、3821、3391。
void compose_solution (int first_digit[4], int i, solution_t *solution)
{
int j, k;
if (i < 4)
{
prime_link_t *link = &prime_link_buff[first_digit[i]];
for (k = 0; k < link->count; k++)
{
int tk = link->list[k];
for (j = 0; j < i && solution->val[j] != tk; j++);
if (j == i)
{
int modula = 1;
solution->val[i] = tk;
for (j = 0; j < 4; j++)
{
int remain = tk%10;
solution->digits[i][3-j] = remain;
tk /= 10;
}
if (check_solution(i, solution))
{
compose_solution(first_digit, i+1, solution);
}
}
}
}
3.3. 判断解矩阵算法
int check_solution(int i, solution_t *solution)
{
int status;
if (i == 0) /*如果矩阵中只有第1列*/
{
/*只要该数的某1位不可能是可逆素数的第1位就返回0*/
status = (prime_link_buff[solution->digits[i][1]].count == 0 ||
prime_link_buff[solution->digits[i][2]].count == 0 ||
prime_link_buff[solution->digits[i][3]].count == 0) ? 0 : 1;
}
else if (i == 3) /*如果矩阵中已有4列*/
{
int j;
int new_number;
for (j = 1; j < 4; j++)
{
int new_number = compose_row_number(j, solution);/*行构成的数*/
if (is_reverse_prime[new_number] == 0)
{
status = 0;
break;
}
}
if (status)
{
new_number = compose_diagonal_number_1(solution); /*对角线1构成的数*/
if (is_reverse_prime[new_number] == 0)
{
status = 0;
}
else
{
new_number = compose_diagonal_number_2(solution); /*对角线2构成的数*/
if (is_reverse_prime[new_number] == 0)
{
status = 0;
}
else
{
/*存放解*/
int k;
for (k = j = 0; k < 4; k++, j += 4)
{
itoa(solution->val[k], &solution_buff[solution_count][j], 10);
}
solution_count++;
}
}
}
}
return status;
}
4. 结果
由于该题的输出结果是唯一的,因此递交评判的程序不必包含计算过程,只要按格式要求输出结果就能AC。
#include<stdio.h>
char *solution[] =
{
"1193100992213191",
"1193102190293911",
"1193120192093911",
"1193122990013191",
"1193704336973911",
"1193725338213319",
"1193725338513319",
"1193745738213719",
"1193796334073911",
"1193900112293191",
"1193901116693911",
"1193901316693911",
"1193902910213911",
"1193904113993371",
"1193920912013911",
"1193922110093191",
"1193925738213319",
"1193925738513319",
"1193947913813917",
"1193966111093911",
"1193966131093911",
"1193992310093191",
"1733106994913371",
"1733128395213319",
"1733128395513319",
"1733148795213719",
"1733194996013371",
"1733922710213719",
"1733993114093911",
"1913100992213911",
"1913102190293191",
"1913103394973191",
"1913106991613191",
"1913106991613391",
"1913120192093191",
"1913122990013911",
"1913143997813917",
"1913161996013191",
"1913190192093391",
"1913720732213719",
"1913794933013191",
"1913900112293911",
"1913900132993911",
"1913902910213191",
"1913917333893391",
"1913920912013191",
"1913922110093911",
"1933128395213719",
"1933128395513719",
"1933161996013191",
"1933902910913191",
"1933913317893391",
"1933983337193191",
"1933987133193391",
"3191100992211193",
"3191100999231193",
"3191102190291913",
"3191109190291933",
"3191120192091913",
"3191122990011193",
"3191330179491913",
"3191371998331933",
"3191702712239173",
"3191900112291193",
"3191902910211913",
"3191916110691913",
"3191920912011913",
"3191922110091193",
"3191934118797193",
"3191949710331913",
"3191960116191913",
"3191960116191933",
"3319382172531193",
"3319382192571193",
"3319385172531193",
"3319385192571193",
"3319952112831733",
"3319955112831733",
"3371139990411193",
"3371382112599133",
"3371382115599133",
"3371722912019173",
"3371784112599173",
"3371949110691733",
"3371960119491733",
"3391178991331933",
"3391331998711933",
"3391338991731913",
"3391382112599173",
"3391382115599173",
"3391916110691913",
"3391920919011913",
"3719102192271733",
"3719322172071913",
"3719382174571193",
"3719952112831933",
"3719952114871733",
"3719955112831933",
"3911100992211913",
"3911102190291193",
"3911110996611193",
"3911120192091193",
"3911122990011913",
"3911140999311733",
"3911166990111193",
"3911166990131193",
"3911310996611193",
"3911329990011913",
"3911340779631193",
"3911352712839133",
"3911352715839133",
"3911369770431193",
"3911752912839133",
"3911752915839133",
"3911754712839173",
"3911900112291913",
"3911902910211193",
"3911920912011193",
"3911922110091913",
"3911974918317193",
"3917138194791193",
"3917978114391913",
"7193183197493911",
"7193187993413191",
"9133125938213371",
"9133128335273911",
"9133128375293911",
"9133155938213371",
"9133158335273911",
"9133158375293911",
"9173120172293371",
"9173122370273191",
"9173125938213391",
"9173125978413371",
"9173128375473911",
"9173155938213391"
};
int main()
{
int i, k;
int count = sizeof(solution) / sizeof(char *);
for (i = 0; i < count; i++)
{
for (k = 0; k < 16; k++)
{
printf("%c", solution[i][k]);
if (k > 0 && k % 4 == 3) printf("/n");
}
if (i < count-1) printf("/n");
}
return 0;
}