51nod 1693 水群(Dijkstra)

分析:一开始想暴力dp,但是有环,不好处理。。考虑建一个图,从k向k-1连一条边权为1,向i*k连一条边权i*k的边,然后Dijkstra,复杂度为O(nlogn(loglog(n)),然而这数据范围。。这时间限制。。

可以简化,只连k乘一个质数p的边,并且p<=13,虽然并不会证明。。可以用未优化过的打个表,发现答案不超过43,因此至少在这个范围内是可行的。。

Dijkstra一开始常数太大了,因为是把边加进去再做的,可以优化成直接利用点得到边。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 #include<vector>
 6 using namespace std;
 7 const int maxn=1e6+10;
 8 int pri[100],len=0;
 9 struct Edge{
10     int from,to,dist;
11     Edge(int u,int v,int d):from(u),to(v),dist(d){}
12 };
13 struct Node{
14     int d,u;
15     Node(int d0,int u0):d(d0),u(u0){}
16 };
17 bool operator < (Node a,Node b){
18     return a.d>b.d;
19 }
20 struct Dijkstra{
21     int n;
22     int d[maxn];
23     void dijkstra(int s){
24         priority_queue<Node> q;
25         for(int i=0;i<n;i++)d[i]=1e9;
26         d[s]=0;
27         q.push(Node(0,s));
28         while(!q.empty()){
29             Node x=q.top();
30             q.pop();
31             int u=x.u;
32             if(d[u]!=x.d)continue;
33             for(int i=0;i<len&&pri[i]*u<=n;i++){
34                 if(d[pri[i]*u]>d[u]+pri[i]){
35                     d[pri[i]*u]=d[u]+pri[i];
36                     q.push(Node(d[pri[i]*u],pri[i]*u));
37                 }
38             }
39             if(u>0&&d[u-1]>d[u]+1){
40                  d[u-1]=d[u]+1;
41                 q.push(Node(d[u-1],u-1));
42             }
43         }
44     }
45 }dij;
46 void CalPri(){
47     int maxn=14;
48     bool no_Pri[maxn];
49     memset(no_Pri,0,sizeof(no_Pri));
50     for(int i=2;i<maxn;i++){
51         if(!no_Pri[i]){
52             pri[len++]=i;
53         }
54         for(int j=0;j<len&&pri[j]*i<maxn;j++){
55             no_Pri[pri[j]*i]=true;
56             if(i%pri[j]==0)break;
57         }
58     }
59 }
60 int main(){
61     CalPri();
62     int n;
63     scanf("%d",&n);
64     dij.n=n+42;
65     dij.dijkstra(1);
66     printf("%d
",dij.d[n]);
67     return 0;
68 }
原文地址:https://www.cnblogs.com/7391-KID/p/7183788.html