0
点赞
收藏
分享

微信扫一扫

最短路 51Nod1693 水群


传送门:​​点击打开链接​​

题意:刚开始只有1个表情,现在有3种操作。操作1.复制,操作2.粘贴,操作3.退格

问要到恰好n个表情,需要的最少的操作数。

思路:这题的思路非常神

首先,我们考虑到把这道题转换成图论,i与i-1之间连一条边,费用为1,i与i*k之间连一条边,费用为k,然后跑一遍最短路。

但是,这里的边数太大了,这里就出现了我们第一个优化,这个优化我觉得值得我们思考。。

在连接i与i*k的边时,只连接k为质数时的点。很容易发现这样是正确的

这也给我们打开了思路,以后遇到乘法的,可以通过质数拆开。

然后是第二个优化,竟然最后k只用到了2,3,5,7,11,13这几个质数。所以被卡题时可以去尝试,看能不能再简化一下数据

然后是最最后一个,,竟然spfa比dijkstra快!我现在终于信spfa了(Orz

#include <map>
#include <set>
#include <cmath>
#include <ctime>
#include <stack>
#include <queue>
#include <cstdio>
#include <cctype>
#include <string>
#include <vector>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;

const int MX = 1e6 + 10;
const int INF = 0x3f3f3f3f;

int d[MX], vis[MX], n;
int prime[] = {0, 2, 3, 5, 7, 11, 13}, prear = 6;

int spfa_bfs(int n) {
queue <int> q;
for(int i = 1; i <= n + 10; i++) {
d[i] = INF; vis[i] = 0;
}
d[1] = 0; vis[1] = 1; q.push(1);
while(!q.empty()) {
int x = q.front(); q.pop(); vis[x] = 0;
for(int j = 1; j <= prear && x * prime[j] < n + 10; j++) {
int y = x * prime[j], cost = prime[j];
if( d[x] + cost < d[y]) {
d[y] = d[x] + cost;
if(!vis[y]) {
vis[y] = 1;
q.push(y);
}
}
}
int y = x - 1, cost = 1;
if( d[x] + cost < d[y]) {
d[y] = d[x] + cost;
if(!vis[y]) {
vis[y] = 1;
q.push(y);
}
}
}
return d[n];
}

int main() {
//FIN;
scanf("%d", &n);
printf("%d\n", spfa_bfs(n));
return 0;
}



举报

相关推荐

0 条评论