51node1693
题目
中文题目
思路
http://blog.csdn.net/mrazer/article/details/51512088这个博主讲的不错。
算是学习了,首先将问题转化为:操作1是s*=k代价为k,操作2是s–代价为1求把s从1变到n的最小代价。
紧接着将k质数分解,让i连接到质数p。
再接着找规律(。。。)发现i→i-1的边不会连续出现4次以上而且i→i*p的边只有当p<=13的时候才有意义,基本上建图就可以做出来了。
还有就是记忆优化的方法,开了个f[maxn][2]的数组,f[][0]与f[][1]我认为一个是只能从连质数那边转来,一个是倒退和连质数都可以,具体看上面链接博主的代码。
感觉值得记的是转化成图的思想,质数分解的方法,打表找规律的方法,还有状态的设计,加油。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int mod=1e9+7;
int zhi[]= {2,3,5,7,11};
struct node
{
int s,dist;
node(int _s,int _dist)
{
s=_s;
dist=_dist;
}
bool operator <(const node &a)const
{
return a.dist<dist;
}
};
int dis[maxn];
int dij(int x)
{
priority_queue<node> q;
while(!q.empty()) q.pop();
memset(dis,0x3f3f3f3f,sizeof(dis));
dis[1]=0;
node p(1,0);
q.push(p);
while(!q.empty())
{
p=q.top(),q.pop();
int to=p.s,diss=p.dist;
if(dis[to]!=diss) continue;
for(int i=0; i<5; i++)
{
int temp=to*zhi[i];
if(temp<x+20&&dis[temp]>dis[to]+zhi[i])
{
dis[temp]=dis[to]+zhi[i];
q.push(node(temp,dis[temp]));
}
}
if(to&&dis[to-1]>dis[to]+1)
{
dis[to-1]=dis[to]+1;
q.push(node(to-1,dis[to-1]));
}
}
return dis[x];
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n",dij(n));
return 0;
}
记忆优化方法:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=1000100;
const int mod=1e9+7;
int zhi[]= {2,3,5,7,11};
int f[maxn][2];
int dfs(int x,int flag)
{
if(x==1) return 0;
if(f[x][flag]) return f[x][flag];
f[x][flag]=0x3f3f3f3f;
for(int i=0; i<5; i++)
if(x%zhi[i]==0)
f[x][flag]=min(f[x][flag],dfs(x/zhi[i],1)+zhi[i]);
if(!flag) return f[x][flag];
f[x][0]=f[x][1];
for(int i=1; i<5; i++)
f[x][flag]=min(f[x][flag],dfs(x+i,0)+i);
return f[x][flag];
}
int main()
{
int n;
scanf("%d",&n);
printf("%d\n",dfs(n,1));
return 0;
}