【原】 POJ 3126 Prime Path 筛素数+BFS单源无权最短路径 解题报告
http://poj.org/problem?id=3126
方法:
先筛出1000~9999的所有素数,对于其中每个素数求得他在图中的邻接点。其邻接点就是所有与其有一位不同的素数。
再用BFS搜索图找到指定源节点和目标节点之间的最短路径。若不联通则输出失败
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
3
1033 8179
1373 8017
1033 1033
Sample Output
6
7
0
1: #include <stdio.h>
2: #include <iostream>
3: #include <vector>
4:
5: using namespace std ;
6:
7: //1000~9999
8: const int N = 10000 ;
9: const int INF = 0x7fffffff ;
10:
11: struct slot
12: {
13: slot():isPrime(1){} //1表示素数,0表示合数
14: int isPrime ;
15: vector<int> adjList ;
16: };
17:
18: typedef vector< struct slot > Graph ;
19:
20: Graph G ;
21: int myQueue[N] ; //自己写队列
22:
23: //n*lglgn
24: void GetPrimeTable()
25: {
26: __int64 i, j ; //必须用__int64,不然j=i*i会超出范围
27:
28: G.resize(N) ;
29: G[0].isPrime = G[1].isPrime= 0 ;
30: i = 2 ;
31: while( i<N )
32: {
33: for( j=i*i ; j<N ; j+=i )
34: G[j].isPrime = 0 ;
35: do ++i ;
36: while( i<N && G[i].isPrime==0 ) ;
37: }
38: }
39:
40: void GetAdjacentList()
41: {
42: int i,j,k,t ;
43: int digit[4] ;
44: int partnum[4] ;
45: int prime,tmpnum ;
46:
47: for( i=1000 ; i<N ; ++i )
48: {
49: if( G[i].isPrime==0 )
50: continue ;
51:
52: prime = tmpnum = i ;
53: //得到每位数字放入digit[]
54: for( j=1000,k=0 ; j>=1 ; j/=10,++k )
55: {
56: digit[k] = tmpnum/j ;
57: tmpnum = tmpnum-digit[k]*j ; //tmp%=j
58: }
59:
60: //得到除去某位的其他各位组成的数
61: partnum[0] = digit[1]*100+digit[2]*10+digit[3] ;
62: partnum[1] = digit[0]*1000+digit[2]*10+digit[3] ;
63: partnum[2] = digit[0]*1000+digit[1]*100+digit[3] ;
64: partnum[3] = digit[0]*1000+digit[1]*100+digit[2]*10 ;
65:
66: //枚举得到邻接表
67: for( j=1 ; j<=9 ; ++j )
68: {
69: tmpnum = j*1000 + partnum[0] ;
70: if( G[tmpnum].isPrime==1 && tmpnum != prime )
71: G[prime].adjList.push_back(tmpnum) ;
72:
73: }
74: for( j=1,t=100 ; j<4 ; ++j,t/=10 )
75: {
76: for( k=0 ; k<=9 ; ++k )
77: {
78: tmpnum = k*t + partnum[j] ;
79: if( G[tmpnum].isPrime==1 && tmpnum != prime )
80: G[prime].adjList.push_back(tmpnum) ;
81:
82: }
83: }
84: }
85: }
86:
87: void run3216()
88: {
89: int n ;
90: int s,t ;
91: bool found ;
92: int curDist ;
93: int vertex,adjVertex ;
94: int front,rear,size ;
95: vector<int>::iterator vIter ;
96:
97: GetPrimeTable() ;
98: GetAdjacentList() ;
99:
100: scanf("%d", &n) ;
101: while( n-- )
102: {
103: found = false ;
104: vector<int> table(N,INF) ; //记录最短距离的table
105:
106: scanf("%d%d", &s,&t) ;
107:
108: size = 0 ;
109: rear = 0 ;
110: front = 1 ;
111:
112: table[s] = 0 ; //起始点最短路径为0
113: myQueue[++rear] = s ; //将起始点入队
114: ++size ;
115: while( size!=0 && !found )
116: {
117: vertex = myQueue[front++] ; //出队
118: --size ;
119: curDist = table[vertex] ; //当前最短路径
120:
121: if( vertex == t ) //搜索到目标节点
122: {
123: printf("%d\n", curDist) ;
124: found = true ;
125: break ;
126: }
127:
128: //将邻接点入队
129: for( vIter=G[vertex].adjList.begin() ; vIter!=G[vertex].adjList.end() ; ++vIter )
130: {
131: adjVertex = *vIter ;
132: if( table[adjVertex]==INF ) //未处理过的
133: {
134: table[adjVertex] = curDist+1 ;
135: if( adjVertex == t ) //搜索到目标节点
136: {
137: printf("%d\n", curDist+1) ;
138: found = true ;
139: break ;
140: }
141:
142: myQueue[++rear] = adjVertex ; //入队
143: ++size ;
144: }
145: }
146: }
147: if( !found )
148: printf( "Impossible" ) ;
149: }
150: }