51node1693 水群(最短路)

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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值