1. 程式人生 > >51nod1693 水群 最短路

51nod1693 水群 最短路

code closed 算數 .... nbsp 分享 nod body pan

若A=K*B,若僅通過操作二:將B變換為A需要K步,

由算數基本定理可知:k=p1*p2*……pn(p為素數,且可能重復)

那麽:將B轉化為p1*B需要p1步,將p1*B轉化為p1*p2*B需要p2步,以此類推,將B轉化為A需要(p1+p2+....pn)步

因為(p1*p2*p3...*pn) < (p1+p2+p3+...pn)故而若僅通過操作二將B轉化為A至少需要(p1+p2+p3...+pn)步

因存在刪除操作,我們將問題轉化為圖論:點i和點k*i之間存在單向邊,點i和點i-1之間存在單項邊。起始點為1,終點為n,求1到n的最短路。

我們知道:若僅通過操作二將1轉化為較大的素數A,需要A步。但若通過操作三,我們可以先將1轉化為(A+m),再通過(A+m)-A步操作,得到A。

例如:A=17,18=2*3*3,將1轉化為18需要8步,再將18轉化為17需要1步,共需要9步,遠小於17。

因而我們可推斷:較大的素數,可以通過操作三由較小的素數推出。

實際上,我們需要的素數僅為(2,3,5,7)

接下來,通過最短路算法,求解

技術分享圖片
#include<stdio.h>
#include<math.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define MAXSIZE 1000005
#define
INF 999999999 #define LL long long using namespace std; int dist[MAXSIZE],p[5]={2,3,5,7}; void spfa() { queue<int> Q; Q.push(1); for(int i=0;i<MAXSIZE;i++) dist[i] = INF; dist[1] = 0; while(!Q.empty()) { int now = Q.front(); Q.pop();
for(int i=0;i<4;i++) { if(p[i]*now<MAXSIZE && dist[now*p[i]]>dist[now]+p[i]) { dist[now*p[i]] = dist[now]+p[i]; Q.push(now*p[i]); } if(now>1 && dist[now-1]>dist[now]+1) { dist[now-1] = dist[now]+1; Q.push(now-1); } } } } int main() { int n; scanf("%d",&n); spfa(); int ans = dist[n]; printf("%d\n",ans); return 0; }
View Code

51nod1693 水群 最短路