现在的位置: 首页 > 综合 > 正文

Prime Path(POJ 3126)解题报告

2018年12月15日 ⁄ 综合 ⁄ 共 6240字 ⁄ 字号 评论关闭

Prime Path(POJ 3126)解题报告

一、原题

Prime Path

Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

The ministers of the cabinet were quite upset by the message from the Chief of Security stating that they would all have to change the four-digit room numbers on their offices. 
— It is a matter of security to change such things every now and then, to keep the enemy in the dark. 
— But look, I have chosen my number 1033 for good reasons. I am the Prime minister, you know! 
— I know, so therefore your new number 8179 is also a prime. You will just have to paste four new digits over the four old ones on your office door. 
— No, it’s not that simple. Suppose that I change the first digit to an 8, then the number will read 8033 which is not a prime! 
— I see, being the prime minister you cannot stand having a non-prime number on your door even for a few seconds. 
— Correct! So I must invent a scheme for going from 1033 to 8179 by a path of prime numbers where only one digit is changed from one prime to the next prime. 

Now, the minister of finance, who had been eavesdropping, intervened. 
— No unnecessary expenditure, please! I happen to know that the price of a digit is one pound. 
— Hmm, in that case I need a computer program to minimize the cost. You don't know some very cheap software gurus, do you? 
— In fact, I do. You see, there is this programming contest going on... Help the prime minister to find the cheapest prime path between any two given four-digit primes! The first digit must be nonzero, of course. Here is a solution in the case above. 

1033
1733
3733
3739
3779
8779
8179

The cost of this solution is 6 pounds. Note that the digit 1 which got pasted over in step 2 can not be reused in the last step – a new 1 must be purchased.

Input

One line with a positive number: the number of test cases (at most 100). Then for each test case, one line with two numbers separated by a blank. Both numbers are four-digit primes (without leading zeros).

Output

One line for each case, either with a number stating the minimal cost or containing the word Impossible.

Sample Input

31033 81791373 80171033 1033

Sample Output

670

 

二、题目大意:

输入两个四位素数,计算将第一个素数转化为第二个素数所需要的最短步数。

要求:

1、每次转化只能swap一个数字,而且用过的数字不能再用

2、每次转化的结果也必须是一个素数

 

三、基本思路:

1、第一个素数用char数组存储,第二个用int存储,用字符串存储对单个位操作时更加便捷(使用了<cstdlib>中的atoi(str1)函数,可将字符串直接转换成长整型整数)。

2、一开始用了struct 来存储

struct P

{

     int num;//结构体里存的x代表当前的操作数是几,t代表已经操作了几次

     int t;

};

大概到第四层很快溢出、、、、囧~

由于用结构体溢出(囧~),这里改用一个step[10000]记录到i个数时当前步数。visited[10000]存储该数字是否被访问过(题目大意1.

 

3、素数表生成函数

int prime[10000];//素数表

void primeTable()//素数表生成

{

    memset(prime,0,sizeof(prime));

    prime[0] = 1;

    prime[1] = 1;

    int i,j;

    for(i = 2 ; i < 10000 ; ++i)

    {

        if(!prime[i])

            for(j = i*i ; j <= 10000 ; j += i)  prime[j] = 1;//1为合数,挖掉质数的平方

    }

}

 

4、用一个int队列存数,将队列顶部元素以字符串形式再度存入num1

status temp_int=que.front();

char temp_str[5];

num1[0]='0'+temp_int/1000;

num1[1]='0'+(temp_int/100)%10;

num1[2]='0'+(temp_int/10)%10;

num1[3]='0'+temp_int%10;

num1[4]='\0';

Ps:最后一句十分关键,由于丢掉这句导致T溢出,需要了解的是strcpy函数根据指针进行赋值,因此最后必须加上\0作为结尾标记。

5BFS关键代码部分:

这部分的嵌套循环实质是对一个数,num1(起始素数)先向上遍历,再向下遍历,找到下一层素数。。(注意向下遍历时需要防止出现0999现象)

for(int i=0; i<4; i++)

{

    for(int j=num1[i]+1; j<='9'; j++)

    {

        strcpy(temp_str,num1);

        temp_str[i]=j;

        status p1= atoi(temp_str);

        if(!visited[p1]&&!prime[p1])//若没被访问过,且新生成的数字temp_str是一个素数

        {

            visited[p1]=true;

            step[p1]=step[temp_int]+1;

            que.push(p1);//压入下一层素数

         }

     }

     for(int j=num1[i]-1; j>='0'; j--)

     {

//其他部分上下均与上一个for相同,只是在if前加上了下面这句

         if(p1<1000)  break;//非常关键,避免出现0999现象

     }

 }

 

 

四、源码完整版

#include <iostream>

#include <cmath>

#include <cstring>

#include <cstdlib>//atoi头文件

#include <queue>

#include <cstdio>

using namespace std;

int step[10000];//记录到i个数时当前步数

int prime[10000];//素数表

bool visited[10000];//一共可能遇到9999-1000个数,只能被访问一次

void primeTable()//素数表生成

{

    memset(prime,0,sizeof(prime));

    prime[0] = 1;

    prime[1] = 1;

    int i,j;

    for(i = 2 ; i < 10000 ; ++i)

    {

        if(!prime[i])

        {

            for(j = i*i ; j <= 10000 ; j += i)

            {

                prime[j] = 1;

            }

        }

    }

}

typedef int status;

int main()

{

    char num1[5];//num1用字符数组存储!

    int num2,T1,ans;

    primeTable();

    cin>>T1;

    while(T1--)

    {

        cin>>num1>>num2;

        if(atoi(num1)==num2)

        {

            cout<<0<<endl;

            continue;

        }

        memset(visited,0,sizeof(visited));

        memset(step,0,sizeof(step));

        ans=0;

        bool flag=false;//表示找到了结果

        queue<status>que;

        que.push(atoi(num1));//p0压入队列

        while(!que.empty())

        {

            status temp_int=que.front();

            char temp_str[5];

            num1[0]='0'+temp_int/1000;//取出各位存入num1

            num1[1]='0'+(temp_int/100)%10;

            num1[2]='0'+(temp_int/10)%10;

            num1[3]='0'+temp_int%10;

            num1[4]='\0';

            visited[temp_int]=true;

            que.pop();

            if(temp_int==num2)

            {

                flag=true;

                cout<<step[num2]<<endl;

                break;

            }

            for(int i=0; i<4; i++)

            {

                for(int j=num1[i]+1; j<='9'; j++)

                {

                    strcpy(temp_str,num1);

                    temp_str[i]=j;

                    status p1= atoi(temp_str);

                    if(!visited[p1]&&!prime[p1])//如果没有被访问过而且新生成的数字temp_str是一个素数

                    {

                        visited[p1]=true;

                        step[p1]=step[temp_int]+1;

                        que.push(p1);

                    }

                }

                for(int j=num1[i]-1; j>='0'; j--)

                {

                    strcpy(temp_str,num1);

                    temp_str[i]=j;

                    status p1= atoi(temp_str);

                    if(p1<1000)  break;

                    if(!visited[p1]&&!prime[p1])//如果没有被访问过而且新生成的数字temp_str是一个素数

                    {

                        visited[p1]=true;

                        step[p1]=step[temp_int]+1;

                        que.push(p1);

                    }

                }

            }

        }

        if(!flag)

            cout<<"Impossible"<<endl;

    }

    return 0;

}

 

 

PS:下完之后发现那个flag好像可以不用的。。。。囧,解题报告处女作,就这样吧, 其实我就是A不下去了

另,附上链接:

http://poj.org/problem?id=3126

抱歉!评论已关闭.