[POJ - 3126 ]E - Prime Path

题目阅读

生词

cabinet [ˈkæbɪnət] n.内阁

every now and then 偶尔

eavesdrop [ˈi:vzdrɒp] vi. 偷听

intervened [ˌɪntəˈvi:nd] v. 介入

expenditure [ɪkˈspendɪtʃə®] n. 花费

Prime minister n.首相

prime n.素数

invent [ɪnˈvent] vt. 创造

scheme [ski:m] n.计划

happen to do 碰巧做某事

guru [ˈgʊru:] n. 专家

题意是有四位数字的素数且最高位不为0的门牌号,如果修改一位需要1磅,并且每次修改的结果都必须是素数,需要找出一条从起始门票号到目标门牌号的修改路径,这条路径的花费要求最小化。

我们可以理解为每个节点代表门牌号,寻找两个素数节点的最短路的问题,无疑要用到BFS。

而生成一个新的素数无疑要修改原数的一位的值,并且要排除重复访问的情况(修改后不能和原数一样,也不能是曾经访问过的数,否则就不满足最短路的必要条件)。似乎容易认为原数是有4个结点的树,每个节点都有9或10种修改的可能。其实可以引用《啊哈算法》再解炸弹人的思路:对于每个结点的修改作为一个单独的方向进行搜索,枚举该位上的各种可能形成临时4位数,如果是素数且未访问过则入队(新节点)

为何不考虑一次修改一个数的多位?因为题目中要求“a path of prime numbers where only one digit is changed from one prime to the next prime.”——每次改变只能修改一个数字

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).

输入的门牌号都是4位素数且最高位不为0。

Output

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

输出最短路的花费或者没有路。

退化情况

1.输入的数值不符合门牌号规则

输入的规则已经排除了这一情况

2.尝试的数值是目标数

结束BFS,输出步数。那么需要用结构体记录当前数值与步数。

struct node{int p,step;
}; 
temp=que.front();if(temp.p==y){cout<

用flag表示找到目标数,用以和找不到目标的区分。

3.修改后的结果不是素数

则不入队,尝试继续修改。这里需要调用判断素数函数,因为需要判断的次数很多。

int isP(int x){for(int i=2;i*i<=x;i++){if(x%i==0){return 0;}}return 1;
}

注意sqrt返回值类型导致i<=sqrt(x)错误,这里直接用i*i<=x表示。

返回非素数0的条件是找到x的因子i,即x%i==0;如果找不到因子,那么x就是素数。

尝试过生成素数表,但是网上题解直接用素数判断函数,虽然这个函数多次调用相对查素数表的时间复杂度可能很大,但至少在题目允许范围内。

4.没有路

由于每次改变只能修改一个数字,对原数每位各自修改后仍然找不出他的素数后继,那么只能认为没有路。在队列角度上就是没有新节点入队导致队空,此时输出impossible.

5.修改后的结果和原数一样,或者访问过这个素数

这就形成了自环,不符合DAG,不入队,继续修改。二者可以通过是否访问过该节点排除。

if(!vis[trial]&&isP(trial))
一般情况

拆分数字:把每位看做修改的大方向,一共有四个方向,每个方向的可能范围是[1,9](最高位不为0)、[0,9](其余位),枚举所有可能,对所有符合要求的可能入队并标记。

			for(j=0;j<=9;j++){trial=temp.p/10*10+j;if(!vis[trial]&&isP(trial)){vis[trial]=1;t.p=trial;t.step=temp.step+1;que.push(t);}}for(j=0;j<=9;j++){trial=temp.p/100*100+j*10+temp.p%10;if(!vis[trial]&&isP(trial)){vis[trial]=1;t.p=trial;t.step=temp.step+1;que.push(t);}}for(j=0;j<=9;j++){trial=temp.p/1000*1000+j*100+temp.p%100;if(!vis[trial]&&isP(trial)){vis[trial]=1;t.p=trial;t.step=temp.step+1;que.push(t);}}for(j=1;j<=9;j++){trial=j*1000+temp.p%1000;if(!vis[trial]&&isP(trial)){vis[trial]=1;t.p=trial;t.step=temp.step+1;que.push(t);}}

枚举可能需要注意不同位的范围不同、用**/和%**获取其它位的数值来组合出试探数。

最后,贴上完整代码

#include
#include
#include
using namespace std;
struct node{int p,step;
}; 
int vis[10000];
int isP(int x){for(int i=2;i*i<=x;i++){if(x%i==0){return 0;}}return 1;
}
int main(){int n,i,j,x,y,step,trial,flag=0;struct node t,temp;freopen("test2.txt","r",stdin);cin>>n;for(i=1;i<=n;i++){cin>>x>>y;flag=0;queue que;memset(vis,0,sizeof(vis));if(x==y){cout<<"0"<


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章